diff --git a/bin/qtmodule-configtests b/bin/qtmodule-configtests new file mode 100755 index 0000000000..f6cc2052da --- /dev/null +++ b/bin/qtmodule-configtests @@ -0,0 +1,340 @@ +#!/usr/bin/perl +###################################################################### +# +# Runs any module configuration tests +# +# Called (currently) from syncqt, and expects a few arguments +# +# configtests $basedir $out_basedir $qtbasedir $quietmode +# +# Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +# Contact: Nokia Corporation (qt-info@nokia.com) +# +###################################################################### + +use strict; +use warnings; + +# use packages ------------------------------------------------------- +use File::Basename; +use File::Path 'mkpath'; +use File::Spec::Functions; +use Cwd; +use Cwd 'abs_path'; +use Config; + +# Which file to look for the %configtests variable in +my $configTestSource = "sync.profile"; + +if ($#ARGV < 3) { + warn "Usage:\n"; + warn " $0 \n"; + exit 1; +} + +# These might be needed in sync.profile +our $basedir = $ARGV[0]; +our $out_basedir = $ARGV[1]; +our $qtbasedir = $ARGV[2]; +my $generator = $ARGV[3]; + +our %configtests; + +my $qmakeCachePath = catfile($out_basedir, ".qmake.cache"); + +my $QMAKE = catfile($qtbasedir, "bin", ($^O =~ /win32/i) ? 'qmake.exe' : 'qmake'); +if (!-x $QMAKE) { + # try the qmake from the path (e.g. this is a shadow build) + $QMAKE = 'qmake'; +} + +# Need to use the right make +# SYMBIAN_UNIX/MINGW should fall back to the non SYMBIAN ones +my $MAKE = 'make'; # default, only works on unix +if ($generator =~ /UNIX|XCODE/i) { # XCODE = make? + $MAKE = 'make'; +} elsif ($generator =~ /MINGW/i) { + $MAKE = 'mingw32-make'; +} elsif ($generator =~ /MSVC.NET|MSBUILD/i) { + $MAKE = 'nmake'; +} else { + # Unhandled (at least): BMAKE, GBUILD, SYMBIAN_ABLD, SYMBIAN_SBSV2 + warn "Unrecognized generator spec ($generator) - assuming '$MAKE'\n"; +} + +###################################################################### +# Syntax: fileContents(filename) +# Params: filename, string, filename of file to return contents +# +# Purpose: Get the contents of a file. +# Returns: String with contents of the file, or empty string if file +# doens't exist. +# Warning: Dies if it does exist but script cannot get read access. +###################################################################### +sub fileContents { + my ($filename) = @_; + my $filecontents = ""; + if (-e $filename) { + open(I, "< $filename") || die "Could not open $filename for reading, read block?"; + local $/; + binmode I; + $filecontents = ; + close I; + } + return $filecontents; +} + +###################################################################### +# Syntax: loadConfigTests() +# +# Purpose: Loads the config tests from the source basedir into %configtests. +# Returns: Nothing +###################################################################### +sub loadConfigTests { + my $configprofile = catfile($basedir, $configTestSource); + my $result; + unless ($result = do $configprofile) { + die "configtests couldn't parse $configprofile: $@\n" if $@; + # We don't check for non null output, since that is valid + } +} + +###################################################################### +# Syntax: hashesAreDifferent +# +# Purpose: Compares two hashes. (must have same key=value for everything) +# Returns: 0 if they are the same, 1 otherwise +###################################################################### +sub hashesAreDifferent { + my %a = %{$_[0]}; + my %b = %{$_[1]}; + + if (keys %a != keys %b) { + return 1; + } + + my %cmp = map { $_ => 1 } keys %a; + for my $key (keys %b) { + last unless exists $cmp{$key}; + last unless $a{$key} eq $b{$key}; + delete $cmp{$key}; + } + if (%cmp) { + return 1; + } else { + return 0; + } +} + +###################################################################### +# Syntax: executeSomething +# Params: A list of things. +# +# Purpose: Executes the first arg, passing the list. +# stderr is redirected to stdout, and the output is captured. +# Returns: The output. +###################################################################### +sub executeSomething { + my ($program, @args) = @_; + + my $pid = open(KID_TO_READ, "-|"); + + my $output; + + if ($pid) { # parent + while () { + $output = $output . $_; + } + close(KID_TO_READ) || $! == 0 || warn "\nFailed to execute $program: exited $?"; + } else { + # redirect STDERR to STDOUT + open STDERR, ">&STDOUT"; + + # Exec something + exec ($program, @args) || die "\nCan't exec $program: $!\n"; + # NOTREACHED + } + + return $output; +} + +###################################################################### +# Syntax: executeTest() +# Params: testName +# +# The testName variable controls the actual config test run - the +# source is assumed to be in $basedir/config.tests/$testName, and +# when 'qmake; make clean; make' is run, is expected to produce a file +# $out_basedir/config.tests/$testName/$testName. If this test passes, +# then 'config_test_$testName = yes' will be written to $out_basedir/.qmake.cache +# +# Purpose: Runs a configuration time test. +# Returns: 0 if the test fails, 1 if it passes, 2 if the test is skipped +# (e.g. .pro file has requires(x) and x is not satisfied) +###################################################################### +sub executeTest { + my ($testName) = @_; + + my $oldWorkingDir = getcwd(); + my $ret = 0; + + my @QMAKEARGS = ('CONFIG-=debug_and_release'); + + my $testOutDir = catdir($out_basedir, 'config.tests', $testName); + + # Since we might be cross compiling, look for barename (Linux) and .exe (Win32/Symbian) + my $testOutFile1 = catfile($testOutDir, "$testName.exe"); + my $testOutFile2 = catfile($testOutDir, $testName); + + if (abs_path($basedir) eq abs_path($out_basedir)) { + chdir $testOutDir or die "\nUnable to change to config test directory ($testOutDir): $!\n"; + } else { # shadow build + if (! -e $testOutDir) { + mkpath $testOutDir or die "\nUnable to create shadow build config test directory ($testOutDir): $!\n"; + } + chdir $testOutDir or die "\nUnable to change to config test directory ($testOutDir): $!\n"; + + push (@QMAKEARGS, catdir($basedir, 'config.tests', $testName)); + } + + # First remove existing stuff (XXX this probably needs generator specific code, but hopefully + # the target removal below will suffice) + if (-e "Makefile") { + executeSomething($MAKE, 'distclean'); + } + + # and any targets that we might find that weren't distcleaned + unlink $testOutFile1, $testOutFile2; + + # Run qmake && make + executeSomething($QMAKE, @QMAKEARGS); + my $makeOutput = executeSomething(($MAKE)); + + # If make prints "blah blah blah\nSkipped." we consider this a skipped test + if ($makeOutput !~ qr(^Skipped\.$)ms) { + # Check the test exists (can't reliably execute, especially for cross compilation) + if (-e $testOutFile1 or -e $testOutFile2) { + $ret = 1; + } + } else { + $ret = 2; + } + + chdir $oldWorkingDir or die "\nUnable to restore working directory: $!\n"; + return $ret; +} + +# Now run configuration tests +# %configtests is a map from config test name to a map of parameters +# e.g: +# +# %configtests = ( +# "simple" => {fatal => 1, message => "Missing required 'simple' component\n"}, +# "failed" => {message => "You need to install the FAILED sdk for this to work\n"} +# ); +# +# Parameters and their defaults: +# - fatal [false] - whether failing this test should abort everything +# - message [""] - A special message to display if this test fails +# +loadConfigTests(); + +# Only do this step for modules that have config tests +# (qtbase doesn't). We try to preserve existing contents (and furthermore +# only write to .qmake.cache if the tests change) +if (abs_path($out_basedir) ne abs_path($qtbasedir)) { + # Read any existing content + my $existingContents = fileContents($qmakeCachePath); + my %oldTestResults; + my %newTestResults; + my @fatalTestsEncountered; + + # Parse the existing results so we can check if we change them + while ($existingContents =~ /^config_test_(.*) = (yes|no)$/gm) { + $oldTestResults{$1} = $2; + } + + # Get the longest length test name so we can pretty print + use List::Util qw(max); + my $maxNameLength = max map { length $_ } keys %configtests; + + # Turn off buffering + $| = 1; + + # Now run the configuration tests + print "Configuration tests:\n"; + + while ((my $testName, my $testParameters) = each %configtests) { + printf " % *s: ", $maxNameLength, $testName; # right aligned, yes/no lines up + + my $fatalTest = $testParameters->{"fatal"} // 0; + my $message = $testParameters->{"message"}; + + my $testResult = executeTest($testName); + my @testResultStrings = ("no\n","yes\n","skipped\n"); + + $newTestResults{$testName} = (($testResult == 1) ? "yes" : "no"); # skipped = no + + if ($testResult == 0) { + # Failed test + if ($fatalTest) { + print "no (fatal)\n"; + # Report the fatality at the end, too + push (@fatalTestsEncountered, $testName); + } else { + print "no\n"; + } + if (defined($message)) { + print $message; + print "\n" unless chop $message eq "\n"; + } + } else { + # yes or skipped + print $testResultStrings[$testResult]; + } + } + + # Check if the test results are different + if (hashesAreDifferent(\%oldTestResults, \%newTestResults)) { + # Generate the new contents + my $newContents = $existingContents; + + # Strip out any existing config test results + $newContents =~ s/^config_test_.*$//gms; + $newContents =~ s/^# Compile time test results.*$//gms; + + # Add any remaining content and make sure we start on a new line + if ($newContents and chop $newContents ne '\n') { + $newContents = $newContents . "\n"; + } + + # Results and header + if (%newTestResults) { + $newContents = $newContents . '# Compile time test results ('.(localtime).")\n"; + + # Results + while ((my $testName, my $testResult) = each %newTestResults) { + $newContents = $newContents . "config_test_$testName = $testResult\n"; + } + } + + # and open the file + open my $cacheFileHandle, ">$qmakeCachePath" or die "Unable to open $qmakeCachePath for writing: $!\n"; + + print $cacheFileHandle $newContents; + + close $cacheFileHandle or die "Unable to close $qmakeCachePath: $!\n"; + } + + # Now see if we have to die + if (@fatalTestsEncountered) { + if ($#fatalTestsEncountered == 0) { + warn "Mandatory configuration test (".$fatalTestsEncountered[0].") failed.\n\n"; + } else { + warn "Mandatory configuration tests (". join (", ", @fatalTestsEncountered) . ") failed.\n\n"; + } + exit -1; + } +} + +exit 0; diff --git a/bin/syncqt b/bin/syncqt index 776ee9c257..0dcbc4d58e 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -15,6 +15,7 @@ use Cwd; use Cwd 'abs_path'; use Config; use strict; +use English qw(-no_match_vars ); # set output basedir to be where ever syncqt is run from our $out_basedir = getcwd(); @@ -38,7 +39,7 @@ our (%modules, %moduleheaders, %classnames, %mastercontent, %modulepris); my $isunix = 0; my $module = 0; my $showonly = 0; -my $quiet = 0; +my $verbose_level = 1; my $remove_stale = 1; my $force_win = 0; my $force_relative = 0; @@ -50,6 +51,7 @@ my $module_fwd = ""; my $cache_module_fwd = 0; my $developer_build = 0; my $no_module_version_header = 0; +my $makefile_generator = ""; my @modules_to_sync ; $force_relative = 1 if ( -d "/System/Library/Frameworks" ); @@ -75,7 +77,9 @@ sub showUsage print " -showonly Show action but not perform (default: " . ($showonly ? "yes" : "no") . ")\n"; print " -outdir Specify output directory for sync (default: $out_basedir)\n"; print " -qtdir Set the path to QtBase (detected: " . (defined $qtbasedir ? $qtbasedir : "-none-") . ")\n"; - print " -quiet Only report problems, not activity (default: " . ($quiet ? "yes" : "no") . ")\n"; + print " -quiet Only report problems, not activity (same as -verbose 0)\n"; + print " -v, -verbose Sets the verbosity level (max. 4) (default: $verbose_level)\n"; + print " The short form increases the level by +1\n"; print " -separate-module ::\n"; print " Create headers for with original headers in\n"; print " relative to \n"; @@ -88,6 +92,7 @@ sub showUsage print " easy development\n"; print " -no-module-version-header\n"; print " Don't create module version header file\n"; + print " -generator Specify the makefile generator setting (e.g. 'UNIX')\n"; print " -help This help\n"; exit 0; } @@ -273,6 +278,15 @@ sub classNames { return @ret; } +sub make_path { + my ($dir, $lib, $be_verbose) = @_; + unless(-e $dir) { + mkpath $dir; + $dir = "" . substr($dir, length($out_basedir)) if ($be_verbose < 3); + print "$lib: mkpath $dir\n" if ($be_verbose > 1); + } +} + ###################################################################### # Syntax: syncHeader(header, iheader, copy, timestamp) # Params: header, string, filename to create "symlink" for @@ -284,14 +298,14 @@ sub classNames { # Returns: 1 if successful, else 0. ###################################################################### sub syncHeader { - my ($header, $iheader, $copy, $ts) = @_; + my ($lib, $header, $iheader, $copy, $ts) = @_; $iheader =~ s=\\=/=g; $header =~ s=\\=/=g; - return copyFile($iheader, $header) if($copy); + return copyFile($lib, $iheader, $header) if($copy); unless(-e $header) { my $header_dir = dirname($header); - mkpath $header_dir, !$quiet; + make_path($header_dir, $lib, $verbose_level); #write it my $iheader_out = fixPaths($iheader, $header_dir); @@ -412,7 +426,7 @@ sub fileCompare { ###################################################################### sub copyFile { - my ($file,$ifile, $copy,$knowdiff,$filecontents,$ifilecontents) = @_; + my ($lib, $file,$ifile, $copy,$knowdiff,$filecontents,$ifilecontents) = @_; # Bi-directional synchronization open( I, "< " . $file ) || die "Could not open $file for reading"; local $/; @@ -434,7 +448,7 @@ sub copyFile if ( $knowdiff || ($filecontents ne $ifilecontents) ) { if ( $copy > 0 ) { my $file_dir = dirname($file); - mkpath $file_dir, !$quiet unless(-e $file_dir); + make_path($file_dir, $lib, $verbose_level); open(O, "> " . $file) || die "Could not open $file for writing (no write permission?)"; local $/; binmode O; @@ -444,7 +458,7 @@ sub copyFile return 1; } elsif ( $copy < 0 ) { my $ifile_dir = dirname($ifile); - mkpath $ifile_dir, !$quiet unless(-e $ifile_dir); + make_path($ifile_dir, $lib, $verbose_level); open(O, "> " . $ifile) || die "Could not open $ifile for writing (no write permission?)"; local $/; binmode O; @@ -468,10 +482,10 @@ sub copyFile ###################################################################### sub symlinkFile { - my ($file,$ifile) = @_; + my ($lib, $file, $ifile) = @_; if ($isunix) { - print "symlink created for $file " unless $quiet; + print "$lib: symlink created for $file " if ($verbose_level); if ( $force_relative && ($ifile =~ /^$quoted_basedir/)) { my $t = getcwd(); my $c = -1; @@ -479,12 +493,12 @@ sub symlinkFile $t =~ s-^$quoted_basedir/--; $p .= "../" while( ($c = index( $t, "/", $c + 1)) != -1 ); $file =~ s-^$quoted_basedir/-$p-; - print " ($file)\n" unless $quiet; + print " ($file)\n" if($verbose_level); } - print "\n" unless $quiet; + print "\n" if($verbose_level); return symlink($file, $ifile); } - return copyFile($file, $ifile); + return copyFile($lib, $file, $ifile); } ###################################################################### @@ -534,8 +548,10 @@ sub findFiles { ###################################################################### sub loadSyncProfile { my ($srcbase, $outbase) = @_; - print("srcbase = $$srcbase \n"); - print("outbase = $$outbase \n"); + if ($verbose_level) { + print(" = $$srcbase \n"); + print(" = $$outbase \n"); + } my $syncprofile = "$$srcbase/sync.profile"; my $result; @@ -627,8 +643,14 @@ while ( @ARGV ) { $var = "showonly"; $val = "yes"; } elsif($arg eq "-quiet") { - $var = "quiet"; + $var = "verbose"; + $val = "0"; + } elsif($arg eq "-v") { + $var = "verbose"; $val = "yes"; + } elsif($arg eq "-verbose") { + $var = "verbose"; + $val = shift @ARGV; } elsif($arg eq "-private") { $var = "create_private_headers"; $val = "yes"; @@ -639,6 +661,9 @@ while ( @ARGV ) { # skip, it's been dealt with at the top of the file shift @ARGV; next; + } elsif($arg eq "-generator") { + $var = "makefile_generator"; + $val = shift @ARGV; } elsif($arg =~/^-/) { print "Unknown option: $arg\n\n" if(!$var); showUsage(); @@ -667,11 +692,13 @@ while ( @ARGV ) { } elsif($showonly) { $showonly--; } - } elsif ($var eq "quiet") { + } elsif ($var eq "verbose") { if($val eq "yes") { - $quiet++; - } elsif($quiet) { - $quiet--; + $verbose_level++; + } elsif($val eq "no" && $verbose_level) { + $verbose_level--; + } else { + $verbose_level = int($val); } } elsif ($var eq "check-includes") { if($val eq "yes") { @@ -698,7 +725,7 @@ while ( @ARGV ) { $force_relative--; } } elsif ($var eq "module") { - print "module :$val:\n" unless $quiet; + print "module :$val:\n" if($verbose_level); die "No such module: $val" unless(defined $modules{$val}); push @modules_to_sync, $val; } elsif ($var eq "separate-module") { @@ -720,6 +747,8 @@ while ( @ARGV ) { $cache_module_fwd = 1; } elsif ($var eq "developer_build") { $developer_build = 1; + } elsif ($var eq "makefile_generator") { + $makefile_generator = $val; } elsif ($var eq "no_module_version_header") { $no_module_version_header = 1; } elsif ($var eq "output") { @@ -766,9 +795,7 @@ loadSyncProfile(\$basedir, \$out_basedir); $isunix = checkUnix; #cache checkUnix # create path -mkpath "$out_basedir/include", !$quiet; -mkpath "$out_basedir/include/Qt", !$quiet; - +make_path("$out_basedir/include/Qt", "", $verbose_level); foreach my $lib (@modules_to_sync) { #iteration info @@ -796,7 +823,7 @@ foreach my $lib (@modules_to_sync) { chomp $module_patch_version; } } - print "WARNING: Module $lib\'s pri missing QT..VERSION variable! Private headers not versioned!\n" if (!$module_version); + print "$lib: WARNING: Module\'s pri missing QT..VERSION variable! Private headers not versioned!\n" if (!$module_version); my $pathtoheaders = ""; $pathtoheaders = $moduleheaders{$lib} if ($moduleheaders{$lib}); @@ -870,6 +897,7 @@ foreach my $lib (@modules_to_sync) { my $modulepri = $modulepris{$lib}; if (-e $modulepri) { my $modulepriname = basename($modulepri); + # FIXME: this creates a file in the source location for shadow-builds my $moduleversionheader = "$modules{$lib}/" . lc($lib) . "version.h"; my $modulehexstring = sprintf("0x%02X%02X%02X", int($module_major_version), int($module_minor_version), int($module_patch_version)); open MODULE_VERSION_HEADER_FILE, ">$moduleversionheader"; @@ -882,8 +910,11 @@ foreach my $lib (@modules_to_sync) { print MODULE_VERSION_HEADER_FILE "#define " .uc($lib) . "_VERSION $modulehexstring\n", ; print MODULE_VERSION_HEADER_FILE "\n"; print MODULE_VERSION_HEADER_FILE "#endif // QT_". uc($lib) . "_VERSION_H\n"; + close MODULE_VERSION_HEADER_FILE; + $moduleversionheader = "" . substr($moduleversionheader, length($basedir)) if ($verbose_level < 2); + print "$lib: created version header $moduleversionheader\n" if($verbose_level); } elsif ($modulepri) { - print "WARNING: Module $lib\'s pri file '$modulepri' not found.\nSkipped creating module version header for $lib.\n"; + print "$lib: WARNING: Module\'s pri file '$modulepri' not found.\n$lib: Skipped creating module version header.\n"; } } @@ -913,6 +944,7 @@ foreach my $lib (@modules_to_sync) { push @headers, "*".$if; } } + my $header_dirname = ""; foreach my $header (@headers) { my $shadow = ($header =~ s/^\*//); $header = 0 if($header =~ /^ui_.*.h/); @@ -979,11 +1011,11 @@ foreach my $lib (@modules_to_sync) { # class =~ s,::,/,g; # } $class_lib_map_contents .= "QT_CLASS_LIB($full_class, $lib, $header_base)\n"; - $header_copies++ if(syncHeader("$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$header", 0, $ts)); + $header_copies++ if(syncHeader($lib, "$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$header", 0, $ts)); # KDE-Compat headers for Phonon if ($lib eq "phonon") { - $header_copies++ if (syncHeader("$out_basedir/include/phonon_compat/Phonon/$class", "$out_basedir/include/$lib/$header", 0, $ts)); + $header_copies++ if (syncHeader($lib, "$out_basedir/include/phonon_compat/Phonon/$class", "$out_basedir/include/$lib/$header", 0, $ts)); } } } elsif ($create_private_headers) { @@ -994,7 +1026,7 @@ foreach my $lib (@modules_to_sync) { } } foreach(@headers) { #sync them - $header_copies++ if(syncHeader($_, $iheader, $copy_headers && !$shadow, $ts)); + $header_copies++ if(syncHeader($lib, $_, $iheader, $copy_headers && !$shadow, $ts)); } if($public_header) { @@ -1023,9 +1055,29 @@ foreach my $lib (@modules_to_sync) { $pri_install_pfiles.= "$pri_install_iheader ";; } } - print "header created for $iheader ($header_copies)\n" if($header_copies > 0 && !$quiet); + + if ($verbose_level && $header_copies) { + my $new_header_dirname = dirname($iheader); + $new_header_dirname = "" . substr($new_header_dirname, length($basedir)) if ($new_header_dirname && $verbose_level < 2); + my $header_base = basename($iheader); + if ($verbose_level < 3) { + my $line_prefix = ","; + if ($new_header_dirname ne $header_dirname) { + $line_prefix = "$lib: created fwd-include header(s) for $new_header_dirname/ {"; + $line_prefix = " }\n".$line_prefix if ($header_dirname); + $header_dirname = $new_header_dirname; + } else { + $line_prefix = ","; + } + print "$line_prefix $header_base ($header_copies)"; + } else { # $verbose_level >= 3 + $iheader = "" . substr($iheader, length($basedir)) if ($verbose_level == 3); + print "$lib: created $header_copies fwd-include headers for $iheader\n"; + } + } } } + print " }\n" if ($header_dirname && $verbose_level > 0 && $verbose_level < 3); } } @@ -1051,11 +1103,11 @@ foreach my $lib (@modules_to_sync) { } if($master_include && $master_contents) { my $master_dir = dirname($master_include); - mkpath $master_dir, !$quiet; - print "header (master) created for $lib\n" unless $quiet; + make_path($master_dir, $lib, $verbose_level); open MASTERINCLUDE, ">$master_include"; print MASTERINCLUDE $master_contents; close MASTERINCLUDE; + print "$lib: created header (master) file\n" if($verbose_level); } } @@ -1076,11 +1128,11 @@ foreach my $lib (@modules_to_sync) { } if($headers_pri_file && $master_contents) { my $headers_pri_dir = dirname($headers_pri_file); - mkpath $headers_pri_dir, !$quiet; - print "headers.pri file created for $lib\n" unless $quiet; + make_path($headers_pri_dir, $lib, $verbose_level); open HEADERS_PRI_FILE, ">$headers_pri_file"; print HEADERS_PRI_FILE $headers_pri_contents; close HEADERS_PRI_FILE; + print "$lib: created headers.pri file\n" if($verbose_level); } # create forwarding module pri in qtbase/mkspecs/modules @@ -1088,7 +1140,7 @@ foreach my $lib (@modules_to_sync) { my $modulepri = $modulepris{$lib}; if (-e $modulepri) { my $modulepriname = basename($modulepri); - mkpath($module_fwd); + make_path($module_fwd, $lib, $verbose_level); my $moduleprifwd = "$module_fwd/$modulepriname"; my $mod_base = $developer_build ? $basedir : $out_basedir; my $mod_component_base = $developer_build ? $qtbasedir : $out_basedir; @@ -1114,7 +1166,7 @@ foreach my $lib (@modules_to_sync) { } } } elsif ($modulepri) { - print "WARNING: Module $lib\'s pri file '$modulepri' not found.\nSkipped creating forwarding pri for $lib.\n"; + print "$lib: WARNING: Module\'s pri file '$modulepri' not found.\n$lib: Skipped creating forwarding pri.\n"; } } } @@ -1132,7 +1184,7 @@ unless($showonly || !$create_uic_class_map) { } if($class_lib_map) { my $class_lib_map_dir = dirname($class_lib_map); - mkpath $class_lib_map_dir, !$quiet; + make_path($class_lib_map_dir, "", $verbose_level); open CLASS_LIB_MAP, ">$class_lib_map"; print CLASS_LIB_MAP $class_lib_map_contents; close CLASS_LIB_MAP; @@ -1216,7 +1268,7 @@ if($check_includes) { if($include) { for my $trylib (keys(%modules)) { if(-e "$out_basedir/include/$trylib/$include") { - print "WARNING: $iheader includes $include when it should include $trylib/$include\n"; + print "$lib: WARNING: $iheader includes $include when it should include $trylib/$include\n"; } } } @@ -1234,27 +1286,27 @@ if($check_includes) { } if ($header_skip_qt_begin_header_test == 0) { if ($qt_begin_header_found == 0) { - print "WARNING: $iheader does not include QT_BEGIN_HEADER\n"; + print "$lib: WARNING: $iheader does not include QT_BEGIN_HEADER\n"; } if ($qt_begin_header_found && $qt_end_header_found == 0) { - print "WARNING: $iheader has QT_BEGIN_HEADER but no QT_END_HEADER\n"; + print "$lib: WARNING: $iheader has QT_BEGIN_HEADER but no QT_END_HEADER\n"; } } if ($header_skip_qt_begin_namespace_test == 0) { if ($qt_begin_namespace_found == 0) { - print "WARNING: $iheader does not include QT_BEGIN_NAMESPACE\n"; + print "$lib: WARNING: $iheader does not include QT_BEGIN_NAMESPACE\n"; } if ($qt_begin_namespace_found && $qt_end_namespace_found == 0) { - print "WARNING: $iheader has QT_BEGIN_NAMESPACE but no QT_END_NAMESPACE\n"; + print "$lib: WARNING: $iheader has QT_BEGIN_NAMESPACE but no QT_END_NAMESPACE\n"; } } if ($header_skip_qt_module_test == 0) { if ($qt_module_found == 0) { - print "WARNING: $iheader does not include QT_MODULE\n"; + print "$lib: WARNING: $iheader does not include QT_MODULE\n"; } } close(F); @@ -1266,4 +1318,21 @@ if($check_includes) { } } +# Do configure tests now (pass some things along) +# fatal tests have a non zero return +# If the generator is not set (e.g. someone invoking syncqt as part of configure etc, then don't run tests either) +unless ($showonly || $makefile_generator eq '') { + my $configtests = dirname($0)."/qtmodule-configtests"; + if (! -f $configtests) { + $configtests = $qtbasedir."/bin/qtmodule-configtests"; + } + if (! -f $configtests) { + warn "Unable to locate qtmodule-configtests script - config tests disabled.\n"; + } else { + if (system($EXECUTABLE_NAME, $configtests, $basedir, $out_basedir, $qtbasedir, $makefile_generator)) { + die "$configtests exited with status $?"; + } + } +} + exit 0; diff --git a/configure b/configure index a3349d468c..be744d3990 100755 --- a/configure +++ b/configure @@ -2577,7 +2577,7 @@ if [ "$OPT_SHADOW" = "yes" ]; then chmod 755 "$outpath/bin/syncqt" fi - for i in elf2e32_qtwrapper createpackage patch_capabilities; do + for i in elf2e32_qtwrapper createpackage patch_capabilities qtmodule-configtests; do rm -f "$outpath/bin/$i" if [ -x "$relpath/bin/$i" ]; then mkdir -p "$outpath/bin" @@ -2970,7 +2970,7 @@ if [ '!' -f "${XQMAKESPEC}/qplatformdefs.h" ]; then echo echo " $XQMAKESPEC/qplatformdefs.h" echo - echo " Please contact qt-bugs@trolltech.com." + echo " Please contact qt-info@nokia.com." echo exit 2 fi @@ -6911,7 +6911,7 @@ fi # For "-carbon" builds: 32 bit x86/ppc. # For builds on snow leopard : compiler default (64-bit). # For builds on leopard : compiler default (32-bit). -if [ "$PLATFORM_MAC" = "yes" ] && [ "$CFG_MAC_ARCHS" = "" ]; then +if [ "$CFG_ARCH" = "macosx" ] && [ "$CFG_MAC_ARCHS" = "" ]; then source "$mactests/defaultarch.test" "$TEST_COMPILER" "$OPT_VERBOSE" "$mactests" if [ "$CFG_MAC_CARBON" = "yes" ]; then @@ -7150,7 +7150,7 @@ fi [ "$CFG_AVX" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG avx" [ "$CFG_IWMMXT" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG iwmmxt" [ "$CFG_NEON" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG neon" -[ "$PLATFORM_MAC" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG $CFG_MAC_ARCHS" +[ "$CFG_ARCH" = "macosx" ] && QMAKE_CONFIG="$QMAKE_CONFIG $CFG_MAC_ARCHS" if [ "$CFG_CLOCK_GETTIME" = "yes" ]; then QT_CONFIG="$QT_CONFIG clock-gettime" fi @@ -8617,7 +8617,7 @@ else echo "Building for: $XPLATFORM" fi -if [ "$PLATFORM_MAC" = "yes" ]; then +if [ ! -z "$CFG_MAC_ARCHS" ]; then echo "Architecture: $CFG_ARCH ($CFG_MAC_ARCHS )" else echo "Architecture: $CFG_ARCH" diff --git a/dist/changes-5.0.0 b/dist/changes-5.0.0 index 344edb6517..523d649573 100644 --- a/dist/changes-5.0.0 +++ b/dist/changes-5.0.0 @@ -17,6 +17,9 @@ information about a particular change. - Unite clipping support has been removed from QPainter. The alternative is to unite QRegion's and using the result on QPainter. +- QLibrary::resolve() now returns a function pointer instead of a void + pointer. + **************************************************************************** * General * **************************************************************************** diff --git a/doc/src/examples/padnavigator.qdoc b/doc/src/examples/padnavigator.qdoc index 0942c82215..591d3d0e63 100644 --- a/doc/src/examples/padnavigator.qdoc +++ b/doc/src/examples/padnavigator.qdoc @@ -316,7 +316,7 @@ Now we construct the \c FlippablePad item, passing its column-row count to its constructor. - The pad is constrolled by three transformations, and we create one + The pad is controlled by three transformations, and we create one QGraphicsRotation object for each of these. \list diff --git a/examples/tools/settingseditor/locationdialog.cpp b/examples/tools/settingseditor/locationdialog.cpp index de7e5bcada..dcf190363a 100644 --- a/examples/tools/settingseditor/locationdialog.cpp +++ b/examples/tools/settingseditor/locationdialog.cpp @@ -54,7 +54,7 @@ LocationDialog::LocationDialog(QWidget *parent) scopeComboBox->addItem(tr("System")); organizationComboBox = new QComboBox; - organizationComboBox->addItem(tr("Trolltech")); + organizationComboBox->addItem(tr("Qt")); organizationComboBox->setEditable(true); applicationComboBox = new QComboBox; diff --git a/examples/tutorials/addressbook-fr/README b/examples/tutorials/addressbook-fr/README index 359859390e..5f82d3ce38 100644 --- a/examples/tutorials/addressbook-fr/README +++ b/examples/tutorials/addressbook-fr/README @@ -39,4 +39,4 @@ qmake -spec macx-xcode Then open the generated Xcode project in Xcode and build it. -Feel free to send comments about the tutorial to qt-bugs@trolltech.com. +Feel free to send comments about the tutorial to qt-info@nokia.com. diff --git a/examples/tutorials/addressbook/README b/examples/tutorials/addressbook/README index 20ae7f3ada..5f364d909c 100644 --- a/examples/tutorials/addressbook/README +++ b/examples/tutorials/addressbook/README @@ -39,4 +39,4 @@ qmake -spec macx-xcode Then open the generated Xcode project in Xcode and build it. -Feel free to send comments about the tutorial to qt-bugs@trolltech.com. +Feel free to send comments about the tutorial to qt-info@nokia.com. diff --git a/mkspecs/features/declarative_debug.prf b/mkspecs/features/declarative_debug.prf new file mode 100644 index 0000000000..b0248f0ac3 --- /dev/null +++ b/mkspecs/features/declarative_debug.prf @@ -0,0 +1 @@ +contains(QT, declarative):DEFINES += QT_DECLARATIVE_DEBUG diff --git a/mkspecs/features/default_pre.prf b/mkspecs/features/default_pre.prf index ebb94e272e..35a4d3f4a4 100644 --- a/mkspecs/features/default_pre.prf +++ b/mkspecs/features/default_pre.prf @@ -2,7 +2,7 @@ load(exclusive_builds) ### Qt 5: remove "uic" and "resources" - or add "qt" CONFIG = lex yacc warn_on debug uic resources $$CONFIG -exists($$_PRO_FILE_PWD_/sync.profile) { +!build_pass:exists($$_PRO_FILE_PWD_/sync.profile) { PRO_BASENAME = $$basename(_PRO_FILE_) # Try to detect proper QTDIR path. We require QTDIR, as syncqt uses that to create qt_module.pri @@ -31,7 +31,7 @@ exists($$_PRO_FILE_PWD_/sync.profile) { qtPrepareTool(QMAKE_SYNCQT, syncqt) - MSG = $$quote($$QMAKE_SYNCQT $$QTFWD -outdir $$OUT_PWD $$_PRO_FILE_PWD_) + MSG = $$quote($$QMAKE_SYNCQT $$QTFWD -generator $$MAKEFILE_GENERATOR -outdir $$OUT_PWD $$_PRO_FILE_PWD_) !silent:message($$MSG) system($$MSG) { # success! Nothing to do diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 86d80cb239..13dadeb1e9 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -140,7 +140,7 @@ defineTest(qtAddModule) { } isEmpty(LINKAGE) { # Make sure we can link to uninstalled libraries - !isEqual(MODULE_LIBS, $[QT_INSTALL_LIBS]) { + !isEqual(MODULE_LIBS, $$[QT_INSTALL_LIBS]) { QMAKE_LIBDIR *= $$MODULE_LIBS unix:!mac:QMAKE_LFLAGS *= "-Wl,-rpath-link,$$MODULE_LIBS" } diff --git a/mkspecs/features/qt_module_config.prf b/mkspecs/features/qt_module_config.prf index 8f225fe6ed..7b5b5ad304 100644 --- a/mkspecs/features/qt_module_config.prf +++ b/mkspecs/features/qt_module_config.prf @@ -186,6 +186,9 @@ DEFINES *= QT_USE_QSTRINGBUILDER TARGET = $$qtLibraryTarget($$TARGET$$QT_LIBINFIX) #do this towards the end +qtPrepareTool(QMAKE_MOC, moc) +qtPrepareTool(QMAKE_UIC, uic) +qtPrepareTool(QMAKE_RCC, rcc) qtPrepareTool(QMAKE_LUPDATE, lupdate) qtPrepareTool(QMAKE_LRELEASE, lrelease) diff --git a/qmake/project.cpp b/qmake/project.cpp index cb4117bef4..bbfd9005c6 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -1382,16 +1382,15 @@ QMakeProject::read(uchar cmd) read(Option::mkfile::cachefile, base_vars); } } - - if(cmd & ReadFeatures) { - debug_msg(1, "Processing default_pre: %s", vars["CONFIG"].join("::").toLatin1().constData()); - if(doProjectInclude("default_pre", IncludeFlagFeature, base_vars) == IncludeNoExist) - doProjectInclude("default", IncludeFlagFeature, base_vars); - } } vars = base_vars; // start with the base + if(cmd & ReadFeatures) { + debug_msg(1, "Processing default_pre: %s", vars["CONFIG"].join("::").toLatin1().constData()); + doProjectInclude("default_pre", IncludeFlagFeature, vars); + } + //get a default if(pfile != "-" && vars["TARGET"].isEmpty()) vars["TARGET"].append(QFileInfo(pfile).baseName()); diff --git a/qtbase.pro b/qtbase.pro index ecbb183471..c28bc9382b 100644 --- a/qtbase.pro +++ b/qtbase.pro @@ -135,6 +135,11 @@ syncqt.files=$$QT_BUILD_TREE/bin/syncqt win32:syncqt.files=$$QT_BUILD_TREE/bin/syncqt.bat INSTALLS += syncqt +#qtmodule-configtests +configtests.path=$$[QT_INSTALL_BINS] +configtests.files=$$QT_BUILD_TREE/bin/qtmodule-configtests +INSTALLS += configtests + #mkspecs mkspecs.path=$$[QT_INSTALL_DATA]/mkspecs mkspecs.files=$$QT_BUILD_TREE/mkspecs/qconfig.pri $$files($$QT_SOURCE_TREE/mkspecs/*) diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-external.h b/src/3rdparty/harfbuzz/src/harfbuzz-external.h index 5fff35fe50..1f7ae1c902 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-external.h +++ b/src/3rdparty/harfbuzz/src/harfbuzz-external.h @@ -144,7 +144,7 @@ HB_CharCategory HB_GetUnicodeCharCategory(HB_UChar32 ch); int HB_GetUnicodeCharCombiningClass(HB_UChar32 ch); HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch); -void *HB_Library_Resolve(const char *library, int version, const char *symbol); +void (*HB_Library_Resolve(const char *library, int version, const char *symbol))(); HB_END_HEADER diff --git a/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp b/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp index f0048b75ef..2c261639ad 100644 --- a/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp +++ b/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp @@ -79,7 +79,7 @@ void HB_GetGraphemeAndLineBreakClass(HB_UChar32 ch, HB_GraphemeClass *grapheme, *lineBreak = (HB_LineBreakClass) prop->line_break_class; } -void *HB_Library_Resolve(const char *library, int version, const char *symbol) +void (*HB_Library_Resolve(const char *library, int version, const char *symbol))() { return QLibrary::resolve(library, version, symbol); } diff --git a/src/corelib/arch/qatomic_bootstrap.h b/src/corelib/arch/qatomic_bootstrap.h index ecce758e71..74dc6cfbb2 100644 --- a/src/corelib/arch/qatomic_bootstrap.h +++ b/src/corelib/arch/qatomic_bootstrap.h @@ -75,13 +75,34 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) return testAndSetOrdered(expectedValue, newValue); } -inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) { int returnValue = _q_value; _q_value += valueToAdd; return returnValue; } +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + + template Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) { diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index a59cbf9382..452679c7d7 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -718,6 +718,13 @@ QT_BEGIN_NAMESPACE \sa QtMsgHandler, qInstallMsgHandler() */ +/*! \typedef QFunctionPointer + \relates + + This is a typedef for \c{void (*)()}, a pointer to a function that takes + no arguments and returns void. +*/ + /*! \macro qint64 Q_INT64_C(literal) \relates diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index e4084ed91f..2f6f33efca 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -281,7 +281,7 @@ namespace QT_NAMESPACE {} # define Q_OS_VXWORKS #elif defined(__MAKEDEPEND__) #else -# error "Qt has not been ported to this OS - talk to qt-bugs@trolltech.com" +# error "Qt has not been ported to this OS - talk to qt-info@nokia.com" #endif #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) || defined(Q_OS_WINCE) @@ -794,7 +794,7 @@ namespace QT_NAMESPACE {} # define Q_CC_NOKIAX86 #else -# error "Qt has not been tested with this compiler - talk to qt-bugs@trolltech.com" +# error "Qt has not been tested with this compiler - talk to qt-info@nokia.com" #endif @@ -1807,6 +1807,8 @@ Q_CORE_EXPORT void qt_message_output(QtMsgType, const char *buf); typedef void (*QtMsgHandler)(QtMsgType, const char *); Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler); +typedef void (*QFunctionPointer)(); + #if !defined(Q_UNIMPLEMENTED) # define Q_UNIMPLEMENTED() qWarning("%s:%d: %s: Unimplemented code.", __FILE__, __LINE__, Q_FUNC_INFO) #endif diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp index 5c5223eb1c..ef302243da 100644 --- a/src/corelib/io/qfilesystemwatcher_inotify.cpp +++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp @@ -131,7 +131,7 @@ # define __NR_inotify_rm_watch 286 # define __NR_inotify_init1 328 #else -# error "This architecture is not supported. Please talk to qt-bugs@trolltech.com" +# error "This architecture is not supported. Please talk to qt-info@nokia.com" #endif #if !defined(IN_CLOEXEC) && defined(O_CLOEXEC) && defined(__NR_inotify_init1) diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index 1b0707605c..10de2caf62 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -45,109 +45,10 @@ #include "qthread.h" #include #include +#include QT_BEGIN_NAMESPACE -// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers -static const int TimerIdMask = 0x00ffffff; -static const int TimerSerialMask = ~TimerIdMask & ~0x80000000; -static const int TimerSerialCounter = TimerIdMask + 1; -static const int MaxTimerId = TimerIdMask; - -static int FirstBucket[] = { - 1, 2, 3, 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 -}; - -enum { - FirstBucketOffset = 0, - SecondBucketOffset = sizeof(FirstBucket) / sizeof(FirstBucket[0]), - ThirdBucketOffset = 0x100, - FourthBucketOffset = 0x1000, - FifthBucketOffset = 0x10000, - SixthBucketOffset = 0x100000 -}; - -enum { - FirstBucketSize = SecondBucketOffset, - SecondBucketSize = ThirdBucketOffset - SecondBucketOffset, - ThirdBucketSize = FourthBucketOffset - ThirdBucketOffset, - FourthBucketSize = FifthBucketOffset - FourthBucketOffset, - FifthBucketSize = SixthBucketOffset - FifthBucketOffset, - SixthBucketSize = MaxTimerId - SixthBucketOffset -}; - -static const int BucketSize[] = { - FirstBucketSize, SecondBucketSize, ThirdBucketSize, - FourthBucketSize, FifthBucketSize, SixthBucketSize -}; -enum { NumberOfBuckets = sizeof(BucketSize) / sizeof(BucketSize[0]) }; - -static const int BucketOffset[] = { - FirstBucketOffset, SecondBucketOffset, ThirdBucketOffset, - FourthBucketOffset, FifthBucketOffset, SixthBucketOffset -}; - -static QBasicAtomicPointer timerIds[] = - { Q_BASIC_ATOMIC_INITIALIZER(FirstBucket), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0) }; - -static void timerIdsDestructorFunction() -{ - // start at one, the first bucket is pre-allocated - for (int i = 1; i < NumberOfBuckets; ++i) - delete [] static_cast(timerIds[i]); -} -Q_DESTRUCTOR_FUNCTION(timerIdsDestructorFunction) - -static QBasicAtomicInt nextFreeTimerId = Q_BASIC_ATOMIC_INITIALIZER(1); - -// avoid the ABA-problem by using 7 of the top 8 bits of the timerId as a serial number -static inline int prepareNewValueWithSerialNumber(int oldId, int newId) -{ - return (newId & TimerIdMask) | ((oldId + TimerSerialCounter) & TimerSerialMask); -} - -namespace { - template struct QStaticAssertType; - template<> struct QStaticAssertType { enum { Value = 1 }; }; -} -#define q_static_assert(expr) (void)QStaticAssertType::Value - -static inline int bucketOffset(int timerId) -{ - q_static_assert(sizeof BucketSize == sizeof BucketOffset); - q_static_assert(sizeof(timerIds) / sizeof(timerIds[0]) == NumberOfBuckets); - - for (int i = 0; i < NumberOfBuckets; ++i) { - if (timerId < BucketSize[i]) - return i; - timerId -= BucketSize[i]; - } - qFatal("QAbstractEventDispatcher: INTERNAL ERROR, timer ID %d is too large", timerId); - return -1; -} - -static inline int bucketIndex(int bucket, int timerId) -{ - return timerId - BucketOffset[bucket]; -} - -static inline int *allocateBucket(int bucket) -{ - // allocate a new bucket - const int size = BucketSize[bucket]; - const int offset = BucketOffset[bucket]; - int *b = new int[size]; - for (int i = 0; i != size; ++i) - b[i] = offset + i + 1; - return b; -} - void QAbstractEventDispatcherPrivate::init() { Q_Q(QAbstractEventDispatcher); @@ -158,79 +59,54 @@ void QAbstractEventDispatcherPrivate::init() } } -// Timer IDs are implemented using a free-list; -// there's a vector initialized with: -// X[i] = i + 1 -// and nextFreeTimerId starts with 1. -// -// Allocating a timer ID involves taking the ID from -// X[nextFreeTimerId] -// updating nextFreeTimerId to this value and returning the old value -// -// When the timer ID is allocated, its cell in the vector is unused (it's a -// free list). As an added protection, we use the cell to store an invalid -// (negative) value that we can later check for integrity. -// -// (continues below). +// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers +struct QtTimerIdFreeListConstants : public QFreeListDefaultConstants +{ + enum + { + InitialNextValue = 1, + BlockCount = 6, + }; + + static const int Sizes[BlockCount]; +}; + +enum { + Offset0 = 0x00000000, + Offset1 = 0x00000040, + Offset2 = 0x00000100, + Offset3 = 0x00001000, + Offset4 = 0x00010000, + Offset5 = 0x00100000, + + Size0 = Offset1 - Offset0, + Size1 = Offset2 - Offset1, + Size2 = Offset3 - Offset2, + Size3 = Offset4 - Offset3, + Size4 = Offset5 - Offset4, + Size5 = QtTimerIdFreeListConstants::MaxIndex - Offset5 +}; + +const int QtTimerIdFreeListConstants::Sizes[QtTimerIdFreeListConstants::BlockCount] = { + Size0, + Size1, + Size2, + Size3, + Size4, + Size5 +}; + +typedef QFreeList QtTimerIdFreeList; +Q_GLOBAL_STATIC(QtTimerIdFreeList, timerIdFreeList) + int QAbstractEventDispatcherPrivate::allocateTimerId() { - int timerId, newTimerId; - int at, *b; - do { - timerId = nextFreeTimerId; //.loadAcquire(); // ### FIXME Proper memory ordering semantics - - // which bucket are we looking in? - int which = timerId & TimerIdMask; - int bucket = bucketOffset(which); - at = bucketIndex(bucket, which); - b = timerIds[bucket]; - - if (!b) { - // allocate a new bucket - b = allocateBucket(bucket); - if (!timerIds[bucket].testAndSetRelease(0, b)) { - // another thread won the race to allocate the bucket - delete [] b; - b = timerIds[bucket]; - } - } - - newTimerId = prepareNewValueWithSerialNumber(timerId, b[at]); - } while (!nextFreeTimerId.testAndSetRelaxed(timerId, newTimerId)); - - b[at] = -timerId; - - return timerId; + return timerIdFreeList()->next(); } -// Releasing a timer ID requires putting the current ID back in the vector; -// we do it by setting: -// X[timerId] = nextFreeTimerId; -// then we update nextFreeTimerId to the timer we've just released -// -// The extra code in allocateTimerId and releaseTimerId are ABA prevention -// and bucket memory. The buckets are simply to make sure we allocate only -// the necessary number of timers. See above. -// -// ABA prevention simply adds a value to 7 of the top 8 bits when resetting -// nextFreeTimerId. void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId) { - int which = timerId & TimerIdMask; - int bucket = bucketOffset(which); - int at = bucketIndex(bucket, which); - int *b = timerIds[bucket]; - - Q_ASSERT_X(timerId == -b[at], "QAbstractEventDispatcher::releaseTimerId", - "Internal error: timer ID not found"); - - int freeId, newTimerId; - do { - freeId = nextFreeTimerId;//.loadAcquire(); // ### FIXME Proper memory ordering semantics - b[at] = freeId & TimerIdMask; - - newTimerId = prepareNewValueWithSerialNumber(freeId, timerId); - } while (!nextFreeTimerId.testAndSetRelease(freeId, newTimerId)); + timerIdFreeList()->release(timerId); } /*! diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index c8ac15c1fa..b6de002cf4 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -859,20 +859,31 @@ QMetaProperty QMetaObject::property(int index) const if (flags & EnumOrFlag) { result.menum = enumerator(indexOfEnumerator(type)); if (!result.menum.isValid()) { - QByteArray enum_name = type; - QByteArray scope_name = d.stringdata; - int s = enum_name.lastIndexOf("::"); - if (s > 0) { - scope_name = enum_name.left(s); - enum_name = enum_name.mid(s + 2); + const char *enum_name = type; + const char *scope_name = d.stringdata; + char *scope_buffer = 0; + + const char *colon = strrchr(enum_name, ':'); + // ':' will always appear in pairs + Q_ASSERT(colon <= enum_name || *(colon-1) == ':'); + if (colon > enum_name) { + int len = colon-enum_name-1; + scope_buffer = (char *)qMalloc(len+1); + qMemCopy(scope_buffer, enum_name, len); + scope_buffer[len] = '\0'; + scope_name = scope_buffer; + enum_name = colon+1; } + const QMetaObject *scope = 0; - if (scope_name == "Qt") + if (qstrcmp(scope_name, "Qt") == 0) scope = &QObject::staticQtMetaObject; else scope = QMetaObject_findMetaObject(this, scope_name); if (scope) result.menum = scope->enumerator(scope->indexOfEnumerator(enum_name)); + if (scope_buffer) + qFree(scope_buffer); } } } diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index 63605ecadb..5da936aab0 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -101,7 +101,8 @@ enum MethodFlags { }; enum MetaObjectFlags { - DynamicMetaObject = 0x01 + DynamicMetaObject = 0x01, + RequiresVariantMetaObject = 0x02 }; class QMutex; diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index a282ae007c..7652ec4871 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -60,7 +60,6 @@ #include #include -#include #include @@ -95,35 +94,22 @@ static int *queuedConnectionTypes(const QList &typeNames) return types; } -static QBasicAtomicPointer signalSlotMutexes = Q_BASIC_ATOMIC_INITIALIZER(0); -static QBasicAtomicInt objectCount = Q_BASIC_ATOMIC_INITIALIZER(0); +static QBasicMutex _q_ObjectMutexPool[131]; /** \internal * mutex to be locked when accessing the connectionlists or the senders list */ static inline QMutex *signalSlotLock(const QObject *o) { - if (!signalSlotMutexes) { - QMutexPool *mp = new QMutexPool; - if (!signalSlotMutexes.testAndSetOrdered(0, mp)) { - delete mp; - } - } - return signalSlotMutexes->get(o); + return static_cast(&_q_ObjectMutexPool[ + uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]); } extern "C" Q_CORE_EXPORT void qt_addObject(QObject *) -{ - objectCount.ref(); -} +{} extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) -{ - if(!objectCount.deref()) { - QMutexPool *old = signalSlotMutexes.fetchAndStoreAcquire(0); - delete old; - } -} +{} struct QConnectionSenderSwitcher { QObject *receiver; @@ -879,7 +865,7 @@ QObject::~QObject() if (c->next) c->next->prev = c->prev; } if (needToUnlock) - m->unlockInline(); + m->unlock(); connectionList.first = c->nextConnectionList; delete c; @@ -903,7 +889,7 @@ QObject::~QObject() bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); //the node has maybe been removed while the mutex was unlocked in relock? if (!node || node->sender != sender) { - m->unlockInline(); + m->unlock(); continue; } node->receiver = 0; @@ -913,7 +899,7 @@ QObject::~QObject() node = node->next; if (needToUnlock) - m->unlockInline(); + m->unlock(); } } @@ -3077,7 +3063,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, } if (needToUnlock) - receiverMutex->unlockInline(); + receiverMutex->unlock(); c->receiver = 0; diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 314ccd7861..45515f32e1 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -447,7 +447,7 @@ QLibraryPrivate::~QLibraryPrivate() } } -void *QLibraryPrivate::resolve(const char *symbol) +QFunctionPointer QLibraryPrivate::resolve(const char *symbol) { if (!pHnd) return 0; @@ -1129,7 +1129,7 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver Note: In Symbian resolving with symbol names works only if the loaded library was built as STDDLL. Otherwise, the ordinals must be used. */ -void *QLibrary::resolve(const char *symbol) +QFunctionPointer QLibrary::resolve(const char *symbol) { if (!isLoaded() && !load()) return 0; @@ -1152,7 +1152,7 @@ void *QLibrary::resolve(const char *symbol) \sa resolve() */ -void *QLibrary::resolve(const QString &fileName, const char *symbol) +QFunctionPointer QLibrary::resolve(const QString &fileName, const char *symbol) { QLibrary library(fileName); return library.resolve(symbol); @@ -1175,7 +1175,7 @@ void *QLibrary::resolve(const QString &fileName, const char *symbol) \sa resolve() */ -void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) +QFunctionPointer QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) { QLibrary library(fileName, verNum); return library.resolve(symbol); @@ -1199,7 +1199,7 @@ void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) \sa resolve() */ -void *QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol) +QFunctionPointer QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol) { QLibrary library(fileName, version); return library.resolve(symbol); diff --git a/src/corelib/plugin/qlibrary.h b/src/corelib/plugin/qlibrary.h index 0154e949b3..e3f557dd7d 100644 --- a/src/corelib/plugin/qlibrary.h +++ b/src/corelib/plugin/qlibrary.h @@ -79,10 +79,10 @@ public: explicit QLibrary(const QString& fileName, const QString &version, QObject *parent = 0); ~QLibrary(); - void *resolve(const char *symbol); - static void *resolve(const QString &fileName, const char *symbol); - static void *resolve(const QString &fileName, int verNum, const char *symbol); - static void *resolve(const QString &fileName, const QString &version, const char *symbol); + QFunctionPointer resolve(const char *symbol); + static QFunctionPointer resolve(const QString &fileName, const char *symbol); + static QFunctionPointer resolve(const QString &fileName, int verNum, const char *symbol); + static QFunctionPointer resolve(const QString &fileName, const QString &version, const char *symbol); bool load(); bool unload(); diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h index 4f66bc26a0..c6804955d9 100644 --- a/src/corelib/plugin/qlibrary_p.h +++ b/src/corelib/plugin/qlibrary_p.h @@ -87,7 +87,7 @@ public: bool loadPlugin(); // loads and resolves instance bool unload(); void release(); - void *resolve(const char *); + QFunctionPointer resolve(const char *); static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString()); @@ -108,7 +108,7 @@ private: bool load_sys(); bool unload_sys(); - void *resolve_sys(const char *); + QFunctionPointer resolve_sys(const char *); QAtomicInt libraryRefCount; QAtomicInt libraryUnloadCount; diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 0a7e841519..d3b08e1acf 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -267,29 +267,29 @@ bool QLibraryPrivate::unload_sys() } #ifdef Q_OS_MAC -Q_CORE_EXPORT void *qt_mac_resolve_sys(void *handle, const char *symbol) +Q_CORE_EXPORT QFunctionPointer qt_mac_resolve_sys(void *handle, const char *symbol) { - return dlsym(handle, symbol); + return QFunctionPointer(dlsym(handle, symbol)); } #endif -void* QLibraryPrivate::resolve_sys(const char* symbol) +QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) { #if defined(QT_AOUT_UNDERSCORE) // older a.out systems add an underscore in front of symbols char* undrscr_symbol = new char[strlen(symbol)+2]; undrscr_symbol[0] = '_'; strcpy(undrscr_symbol+1, symbol); - void* address = dlsym(pHnd, undrscr_symbol); + QFunctionPointer address = QFunctionPointer(dlsym(pHnd, undrscr_symbol)); delete [] undrscr_symbol; #elif defined(QT_HPUX_LD) - void* address = 0; + QFunctionPointer address = 0; if (shl_findsym((shl_t*)&pHnd, symbol, TYPE_UNDEFINED, &address) < 0) address = 0; #elif defined (QT_NO_DYNAMIC_LIBRARY) - void *address = 0; + QFunctionPointer address = 0; #else - void* address = dlsym(pHnd, symbol); + QFunctionPointer address = QFunctionPointer(dlsym(pHnd, symbol)); #endif if (!address) { errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( diff --git a/src/corelib/plugin/qlibrary_win.cpp b/src/corelib/plugin/qlibrary_win.cpp index 667d9cca45..4eeb2fc441 100644 --- a/src/corelib/plugin/qlibrary_win.cpp +++ b/src/corelib/plugin/qlibrary_win.cpp @@ -113,12 +113,12 @@ bool QLibraryPrivate::unload_sys() return true; } -void* QLibraryPrivate::resolve_sys(const char* symbol) +QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) { #ifdef Q_OS_WINCE - void* address = (void*)GetProcAddress(pHnd, (const wchar_t*)QString::fromLatin1(symbol).utf16()); + FARPROC address = GetProcAddress(pHnd, (const wchar_t*)QString::fromLatin1(symbol).utf16()); #else - void* address = (void*)GetProcAddress(pHnd, symbol); + FARPROC address = GetProcAddress(pHnd, symbol); #endif if (!address) { errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( @@ -126,6 +126,6 @@ void* QLibraryPrivate::resolve_sys(const char* symbol) } else { errorString.clear(); } - return address; + return QFunctionPointer(address); } QT_END_NAMESPACE diff --git a/src/corelib/plugin/qsystemlibrary_p.h b/src/corelib/plugin/qsystemlibrary_p.h index f20d0b6b9d..3298f05b8f 100644 --- a/src/corelib/plugin/qsystemlibrary_p.h +++ b/src/corelib/plugin/qsystemlibrary_p.h @@ -78,20 +78,20 @@ public: return (m_handle != 0); } - void *resolve(const char *symbol) + QFunctionPointer resolve(const char *symbol) { if (!m_didLoad) load(); if (!m_handle) return 0; #ifdef Q_OS_WINCE - return (void*)GetProcAddress(m_handle, (const wchar_t*)QString::fromLatin1(symbol).utf16()); + return QFunctionPointer(GetProcAddress(m_handle, (const wchar_t*)QString::fromLatin1(symbol).utf16())); #else - return (void*)GetProcAddress(m_handle, symbol); + return QFunctionPointer(GetProcAddress(m_handle, symbol)); #endif } - static void *resolve(const QString &libraryName, const char *symbol) + static QFunctionPointer resolve(const QString &libraryName, const char *symbol) { return QSystemLibrary(libraryName).resolve(symbol); } diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 3e3bf8ff13..c90b44be6c 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -49,8 +49,25 @@ #include "qthread.h" #include "qmutex_p.h" +#ifndef Q_OS_LINUX +#include "private/qfreelist_p.h" +#endif + QT_BEGIN_NAMESPACE +/*! + \class QBasicMutex + \brief QMutex POD + \internal + + \ingroup thread + + - Can be used as global static object. + - Always non-recursive + - Do not use tryLock with timeout > 0, else you can have a leak (see the ~QMutex destructor) +*/ + + /*! \class QMutex \brief The QMutex class provides access serialization between threads. @@ -122,8 +139,12 @@ QT_BEGIN_NAMESPACE \sa lock(), unlock() */ QMutex::QMutex(RecursionMode mode) - : d(new QMutexPrivate(mode)) -{ } +{ + if (mode == Recursive) + d = new QRecursiveMutexPrivate; + else + d = 0; +} /*! Destroys the mutex. @@ -131,9 +152,18 @@ QMutex::QMutex(RecursionMode mode) \warning Destroying a locked mutex may result in undefined behavior. */ QMutex::~QMutex() -{ delete static_cast(d); } +{ + if (isRecursive()) + delete static_cast(d._q_value); + else if (d) { +#ifndef Q_OS_LINUX + if (d->possiblyUnlocked && tryLock()) { unlock(); return; } +#endif + qWarning("QMutex: destroying locked mutex"); + } +} -/*! +/*! \fn void QMutex::lock() Locks the mutex. If another thread has locked the mutex then this call will block until that thread has unlocked it. @@ -145,40 +175,8 @@ QMutex::~QMutex() \sa unlock() */ -void QMutex::lock() -{ - QMutexPrivate *d = static_cast(this->d); - Qt::HANDLE self; - if (d->recursive) { - self = QThread::currentThreadId(); - if (d->owner == self) { - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter"); - return; - } - - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - // didn't get the lock, wait for it - isLocked = d->wait(); - Q_ASSERT_X(isLocked, "QMutex::lock", - "Internal error, infinite wait has timed out."); - } - - d->owner = self; - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter"); - return; - } - - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - lockInternal(); - } -} - -/*! +/*!\fn bool QMutex::trylock() Attempts to lock the mutex. If the lock was obtained, this function returns true. If another thread has locked the mutex, this function returns false immediately. @@ -195,36 +193,9 @@ void QMutex::lock() \sa lock(), unlock() */ -bool QMutex::tryLock() -{ - QMutexPrivate *d = static_cast(this->d); - Qt::HANDLE self; - if (d->recursive) { - self = QThread::currentThreadId(); - if (d->owner == self) { - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return true; - } - - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - // some other thread has the mutex locked, or we tried to - // recursively lock an non-recursive mutex - return isLocked; - } - - d->owner = self; - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return isLocked; - } - - return d->contenders.testAndSetAcquire(0, 1); -} - -/*! \overload +/*! \fn bool QMutex::tryLock(int timeout) + \overload Attempts to lock the mutex. This function returns true if the lock was obtained; otherwise it returns false. If another thread has @@ -247,81 +218,30 @@ bool QMutex::tryLock() \sa lock(), unlock() */ -bool QMutex::tryLock(int timeout) -{ - QMutexPrivate *d = static_cast(this->d); - Qt::HANDLE self; - - if (d->recursive) { - self = QThread::currentThreadId(); - if (d->owner == self) { - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return true; - } - - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - // didn't get the lock, wait for it - isLocked = d->wait(timeout); - if (!isLocked) - return false; - } - - d->owner = self; - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return true; - } - - return (d->contenders.testAndSetAcquire(0, 1) - // didn't get the lock, wait for it - || d->wait(timeout)); -} -/*! +/*! \fn void QMutex::unlock() Unlocks the mutex. Attempting to unlock a mutex in a different thread to the one that locked it results in an error. Unlocking a mutex that is not locked results in undefined behavior. \sa lock() */ -void QMutex::unlock() -{ - QMutexPrivate *d = static_cast(this->d); - if (d->recursive) { - if (!--d->count) { - d->owner = 0; - if (!d->contenders.testAndSetRelease(1, 0)) - d->wakeUp(); - } - } else { - if (!d->contenders.testAndSetRelease(1, 0)) - d->wakeUp(); - } -} /*! - \fn bool QMutex::locked() + \fn void QMutex::isRecursive() + \since 5.0 - Returns true if the mutex is locked by another thread; otherwise - returns false. + Returns true if the mutex is recursive - It is generally a bad idea to use this function, because code - that uses it has a race condition. Use tryLock() and unlock() - instead. - - \oldcode - bool isLocked = mutex.locked(); - \newcode - bool isLocked = true; - if (mutex.tryLock()) { - mutex.unlock(); - isLocked = false; - } - \endcode */ +bool QBasicMutex::isRecursive() { + QMutexPrivate *d = this->d; + if (quintptr(d) <= 0x3) + return false; + return d->recursive; +} + /*! \class QMutexLocker @@ -418,96 +338,217 @@ void QMutex::unlock() \sa unlock() */ +#ifndef Q_OS_LINUX //linux implementation is in qmutex_linux.cpp /*! - \fn QMutex::QMutex(bool recursive) - - Use the constructor that takes a RecursionMode parameter instead. -*/ - -/*! - \internal helper for lockInline() + \internal helper for lock() */ -void QMutex::lockInternal() +bool QBasicMutex::lockInternal(int timeout) { - QMutexPrivate *d = static_cast(this->d); + while (!fastTryLock()) { + QMutexPrivate *d = this->d; + if (!d) // if d is 0, the mutex is unlocked + continue; - if (QThread::idealThreadCount() == 1) { - // don't spin on single cpu machines - bool isLocked = d->wait(); - Q_ASSERT_X(isLocked, "QMutex::lock", - "Internal error, infinite wait has timed out."); - Q_UNUSED(isLocked); - return; - } - - QElapsedTimer elapsedTimer; - elapsedTimer.start(); - do { - qint64 spinTime = elapsedTimer.nsecsElapsed(); - if (spinTime > d->maximumSpinTime) { - // didn't get the lock, wait for it, since we're not going to gain anything by spinning more - elapsedTimer.start(); - bool isLocked = d->wait(); - Q_ASSERT_X(isLocked, "QMutex::lock", - "Internal error, infinite wait has timed out."); - Q_UNUSED(isLocked); - - qint64 maximumSpinTime = d->maximumSpinTime; - qint64 averageWaitTime = d->averageWaitTime; - qint64 actualWaitTime = elapsedTimer.nsecsElapsed(); - if (actualWaitTime < (QMutexPrivate::MaximumSpinTimeThreshold * 3 / 2)) { - // measure the wait times - averageWaitTime = d->averageWaitTime = qMin((averageWaitTime + actualWaitTime) / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold)); + if (d == dummyLocked()) { + if (timeout == 0) + return false; + QMutexPrivate *newD = QMutexPrivate::allocate(); + if (!this->d.testAndSetOrdered(d, newD)) { + //Either the mutex is already unlocked, or another thread already set it. + newD->deref(); + continue; } - - // adjust the spin count when spinning does not benefit contention performance - if ((spinTime + actualWaitTime) - qint64(QMutexPrivate::MaximumSpinTimeThreshold) >= qint64(QMutexPrivate::MaximumSpinTimeThreshold)) { - // long waits, stop spinning - d->maximumSpinTime = 0; - } else { - // allow spinning if wait times decrease, but never spin more than the average wait time (otherwise we may perform worse) - d->maximumSpinTime = qBound(qint64(averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold)); - } - return; + d = newD; + //the d->refCount is already 1 the deref will occurs when we unlock + } else if (d->recursive) { + return static_cast(d)->lock(timeout); } - // be a good citizen... yielding lets something else run if there is something to run, but may also relieve memory pressure if not - QThread::yieldCurrentThread(); - } while (d->contenders != 0 || !d->contenders.testAndSetAcquire(0, 1)); - // spinning is working, do not change the spin time (unless we are using much less time than allowed to spin) - qint64 maximumSpinTime = d->maximumSpinTime; - qint64 spinTime = elapsedTimer.nsecsElapsed(); - if (spinTime < maximumSpinTime / 2) { - // we are using much less time than we need, adjust the limit - d->maximumSpinTime = qBound(qint64(d->averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold)); + if (timeout == 0 && !d->possiblyUnlocked) + return false; + + if (!d->ref()) + continue; //that QMutexPrivate was already released + + if (d != this->d) { + //Either the mutex is already unlocked, or relocked with another mutex + d->deref(); + continue; + } + + int old_waiters; + do { + old_waiters = d->waiters; + if (old_waiters == -QMutexPrivate::BigNumber) { + // we are unlocking, and the thread that unlocks is about to change d to 0 + // we try to aquire the mutex by changing to dummyLocked() + if (this->d.testAndSetAcquire(d, dummyLocked())) { + // Mutex aquired + Q_ASSERT(d->waiters == -QMutexPrivate::BigNumber || d->waiters == 0); + d->waiters = 0; + d->deref(); + return true; + } else { + Q_ASSERT(d != this->d); //else testAndSetAcquire should have succeeded + // Mutex is likely to bo 0, we should continue the outer-loop, + // set old_waiters to the magic value of BigNumber + old_waiters = QMutexPrivate::BigNumber; + break; + } + } + } while (!d->waiters.testAndSetRelaxed(old_waiters, old_waiters + 1)); + + if (d != this->d) { + // Mutex was unlocked. + if (old_waiters != QMutexPrivate::BigNumber) { + //we did not break the previous loop + Q_ASSERT(d->waiters >= 1); + d->waiters.deref(); + } + d->deref(); + continue; + } + + if (d->wait(timeout)) { + if (d->possiblyUnlocked && d->possiblyUnlocked.testAndSetRelaxed(true, false)) + d->deref(); + d->derefWaiters(1); + //we got the lock. (do not deref) + Q_ASSERT(d == this->d); + return true; + } else { + Q_ASSERT(timeout >= 0); + //timeout + d->derefWaiters(1); + //There may be a race in which the mutex is unlocked right after we timed out, + // and before we deref the waiters, so maybe the mutex is actually unlocked. + if (!d->possiblyUnlocked.testAndSetRelaxed(false, true)) + d->deref(); + return false; + } } + Q_ASSERT(this->d); + return true; } /*! \internal */ -void QMutex::unlockInternal() +void QBasicMutex::unlockInternal() { - static_cast(d)->wakeUp(); + QMutexPrivate *d = this->d; + Q_ASSERT(d); //we must be locked + Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed + + if (d->recursive) { + static_cast(d)->unlock(); + return; + } + + if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) { + //there is no one waiting on this mutex anymore, set the mutex as unlocked (d = 0) + if (this->d.testAndSetRelease(d, 0)) { + if (d->possiblyUnlocked && d->possiblyUnlocked.testAndSetRelaxed(true, false)) + d->deref(); + } + d->derefWaiters(0); + } else { + d->derefWaiters(0); + //there are thread waiting, transfer the lock. + d->wakeUp(); + } + d->deref(); +} + +//The freelist managment +namespace { +struct FreeListConstants : QFreeListDefaultConstants { + enum { BlockCount = 4, MaxIndex=0xffff }; + static const int Sizes[BlockCount]; +}; +const int FreeListConstants::Sizes[FreeListConstants::BlockCount] = { + 16, + 128, + 1024, + FreeListConstants::MaxIndex - (16-128-1024) +}; + +typedef QFreeList FreeList; +Q_GLOBAL_STATIC(FreeList, freelist); +} + +QMutexPrivate *QMutexPrivate::allocate() +{ + int i = freelist()->next(); + QMutexPrivate *d = &(*freelist())[i]; + d->id = i; + Q_ASSERT(d->refCount == 0); + Q_ASSERT(!d->recursive); + Q_ASSERT(!d->possiblyUnlocked); + Q_ASSERT(d->waiters == 0); + d->refCount = 1; + return d; +} + +void QMutexPrivate::release() +{ + Q_ASSERT(!recursive); + Q_ASSERT(refCount == 0); + Q_ASSERT(!possiblyUnlocked); + Q_ASSERT(waiters == 0); + freelist()->release(id); +} + +// atomically substract "value" to the waiters, and remove the QMutexPrivate::BigNumber flag +void QMutexPrivate::derefWaiters(int value) +{ + int old_waiters; + int new_waiters; + do { + old_waiters = waiters; + new_waiters = old_waiters; + if (new_waiters < 0) { + new_waiters += QMutexPrivate::BigNumber; + } + new_waiters -= value; + } while (!waiters.testAndSetRelaxed(old_waiters, new_waiters)); +} +#endif + +/*! + \internal + */ +bool QRecursiveMutexPrivate::lock(int timeout) { + Qt::HANDLE self = QThread::currentThreadId(); + if (owner == self) { + ++count; + Q_ASSERT_X(count != 0, "QMutex::lock", "Overflow in recursion counter"); + return true; + } + bool success = true; + if (timeout == -1) { + mutex.lock(); + } else { + success = mutex.tryLock(timeout); + } + + if (success) + owner = self; + return success; } /*! - \fn QMutex::lockInline() \internal - inline version of QMutex::lock() -*/ - -/*! - \fn QMutex::unlockInline() - \internal - inline version of QMutex::unlock() -*/ - -/*! - \fn QMutex::tryLockInline() - \internal - inline version of QMutex::tryLock() -*/ + */ +void QRecursiveMutexPrivate::unlock() +{ + if (count > 0) { + count--; + } else { + owner = 0; + mutex.unlock(); + } +} QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index cc667560db..a49b981d01 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -52,47 +52,64 @@ QT_BEGIN_NAMESPACE QT_MODULE(Core) -#ifndef QT_NO_THREAD +#if !defined(QT_NO_THREAD) && !defined(qdoc) -class QAtomicInt; -class QMutexData; +class QMutexPrivate; -class Q_CORE_EXPORT QMutex +class Q_CORE_EXPORT QBasicMutex { - friend class QWaitCondition; - friend class QWaitConditionPrivate; - public: - enum RecursionMode { NonRecursive, Recursive }; + inline void lock() { + if (!fastTryLock()) + lockInternal(); + } - explicit QMutex(RecursionMode mode = NonRecursive); - ~QMutex(); + inline void unlock() { + Q_ASSERT(d); //mutex must be locked + if (!d.testAndSetRelease(dummyLocked(), 0)) + unlockInternal(); + } - void lock(); //### Qt5: make inline; - inline void lockInline(); - bool tryLock(); //### Qt5: make inline; - bool tryLock(int timeout); - inline bool tryLockInline(); - void unlock(); //### Qt5: make inline; - inline void unlockInline(); + bool tryLock(int timeout = 0) { + return fastTryLock() || lockInternal(timeout); + } + + bool isRecursive(); private: - void lockInternal(); + inline bool fastTryLock() { + return d.testAndSetAcquire(0, dummyLocked()); + } + bool lockInternal(int timeout = -1); void unlockInternal(); - Q_DISABLE_COPY(QMutex) - QMutexData *d; + QBasicAtomicPointer d; + static inline QMutexPrivate *dummyLocked() { + return reinterpret_cast(quintptr(1)); + } + + friend class QMutex; + friend class QMutexPrivate; +}; + +class Q_CORE_EXPORT QMutex : public QBasicMutex { +public: + enum RecursionMode { NonRecursive, Recursive }; + explicit QMutex(RecursionMode mode = NonRecursive); + ~QMutex(); +private: + Q_DISABLE_COPY(QMutex) }; class Q_CORE_EXPORT QMutexLocker { public: - inline explicit QMutexLocker(QMutex *m) + inline explicit QMutexLocker(QBasicMutex *m) { Q_ASSERT_X((reinterpret_cast(m) & quintptr(1u)) == quintptr(0), "QMutexLocker", "QMutex pointer is misaligned"); if (m) { - m->lockInline(); + m->lock(); val = reinterpret_cast(m) | quintptr(1u); } else { val = 0; @@ -104,7 +121,7 @@ public: { if ((val & quintptr(1u)) == quintptr(1u)) { val &= ~quintptr(1u); - mutex()->unlockInline(); + mutex()->unlock(); } } @@ -112,7 +129,7 @@ public: { if (val) { if ((val & quintptr(1u)) == quintptr(0u)) { - mutex()->lockInline(); + mutex()->lock(); val |= quintptr(1u); } } @@ -138,54 +155,9 @@ private: quintptr val; }; -class QMutexData -{ - public: - QAtomicInt contenders; - const uint recursive : 1; - uint reserved : 31; - protected: - QMutexData(QMutex::RecursionMode mode); - ~QMutexData(); -}; - -#ifdef QT_NO_DEBUG -inline void QMutex::unlockInline() -{ - if (d->recursive) { - unlock(); - } else if (!d->contenders.testAndSetRelease(1, 0)) { - unlockInternal(); - } -} - -inline bool QMutex::tryLockInline() -{ - if (d->recursive) { - return tryLock(); - } else { - return d->contenders.testAndSetAcquire(0, 1); - } -} - -inline void QMutex::lockInline() -{ - if (d->recursive) { - lock(); - } else if(!tryLockInline()) { - lockInternal(); - } -} -#else // QT_NO_DEBUG -//in debug we do not use inline calls in order to allow debugging tools -// to hook the mutex locking functions. -inline void QMutex::unlockInline() { unlock(); } -inline bool QMutex::tryLockInline() { return tryLock(); } -inline void QMutex::lockInline() { lock(); } -#endif // QT_NO_DEBUG -#else // QT_NO_THREAD +#else // QT_NO_THREAD or qdoc class Q_CORE_EXPORT QMutex @@ -194,14 +166,11 @@ public: enum RecursionMode { NonRecursive, Recursive }; inline explicit QMutex(RecursionMode mode = NonRecursive) { Q_UNUSED(mode); } - inline ~QMutex() {} static inline void lock() {} - static inline void lockInline() {} static inline bool tryLock(int timeout = 0) { Q_UNUSED(timeout); return true; } - static inline bool tryLockInline() { return true; } static inline void unlock() {} - static inline void unlockInline() {} + static inline bool isRecursive() { return true; } private: Q_DISABLE_COPY(QMutex) @@ -221,7 +190,9 @@ private: Q_DISABLE_COPY(QMutexLocker) }; -#endif // QT_NO_THREAD +typedef QMutex QBasicMutex; + +#endif // QT_NO_THREAD or qdoc QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex_linux.cpp b/src/corelib/thread/qmutex_linux.cpp new file mode 100644 index 0000000000..17015b8f84 --- /dev/null +++ b/src/corelib/thread/qmutex_linux.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qmutex.h" + +#ifndef QT_NO_THREAD +#include "qatomic.h" +#include "qmutex_p.h" +# include "qelapsedtimer.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static inline int _q_futex(QMutexPrivate *volatile *addr, int op, int val, const struct timespec *timeout) +{ + volatile int *int_addr = reinterpret_cast(addr); +#if Q_BYTE_ORDER == Q_BIG_ENDIAN && QT_POINTER_SIZE == 8 + int_addr++; //We want a pointer to the 32 least significant bit of QMutex::d +#endif + int *addr2 = 0; + int val2 = 0; + return syscall(SYS_futex, int_addr, op, val, timeout, addr2, val2); +} + +static inline QMutexPrivate *dummyFutexValue() +{ + return reinterpret_cast(quintptr(3)); +} + + +QMutexPrivate::~QMutexPrivate() {} +QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) + : recursive(mode == QMutex::Recursive) {} + +bool QBasicMutex::lockInternal(int timeout) +{ + QElapsedTimer elapsedTimer; + if (timeout >= 1) + elapsedTimer.start(); + + while (!fastTryLock()) { + QMutexPrivate *d = this->d; + if (!d) // if d is 0, the mutex is unlocked + continue; + + if (quintptr(d) <= 0x3) { //d == dummyLocked() || d == dummyFutexValue() + if (timeout == 0) + return false; + while (this->d.fetchAndStoreAcquire(dummyFutexValue()) != 0) { + struct timespec ts, *pts = 0; + if (timeout >= 1) { + // recalculate the timeout + qint64 xtimeout = timeout * 1000 * 1000; + xtimeout -= elapsedTimer.nsecsElapsed(); + if (xtimeout <= 0) { + // timer expired after we returned + return false; + } + ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000; + ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000); + pts = &ts; + } + int r = _q_futex(&this->d._q_value, FUTEX_WAIT, quintptr(dummyFutexValue()), pts); + if (r != 0 && errno == ETIMEDOUT) + return false; + } + return true; + } + Q_ASSERT(d->recursive); + return static_cast(d)->lock(timeout); + } + Q_ASSERT(this->d); + return true; +} + +void QBasicMutex::unlockInternal() +{ + QMutexPrivate *d = this->d; + Q_ASSERT(d); //we must be locked + Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed + + if (d == dummyFutexValue()) { + this->d.fetchAndStoreRelease(0); + _q_futex(&this->d._q_value, FUTEX_WAKE, 1, 0); + return; + } + + Q_ASSERT(d->recursive); + static_cast(d)->unlock(); +} + + +QT_END_NAMESPACE + +#endif // QT_NO_THREAD diff --git a/src/corelib/thread/qmutex_mac.cpp b/src/corelib/thread/qmutex_mac.cpp new file mode 100644 index 0000000000..f63feebca4 --- /dev/null +++ b/src/corelib/thread/qmutex_mac.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qmutex.h" + +#if !defined(QT_NO_THREAD) + +#include "qmutex_p.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) + : recursive(mode == QMutex::Recursive) +{ + kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); + if (r != KERN_SUCCESS) + qWarning("QMutex: failed to create semaphore, error %d", r); +} + +QMutexPrivate::~QMutexPrivate() +{ + kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore); + if (r != KERN_SUCCESS) + qWarning("QMutex: failed to destroy semaphore, error %d", r); +} + +bool QMutexPrivate::wait(int timeout) +{ + kern_return_t r; + if (timeout < 0) { + do { + r = semaphore_wait(mach_semaphore); + } while (r == KERN_ABORTED); + Q_ASSERT(r == KERN_SUCCESS); + } else { + mach_timespec_t ts; + ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; + ts.tv_sec = (timeout / 1000); + r = semaphore_timedwait(mach_semaphore, ts); + } + return (r == KERN_SUCCESS); +} + +void QMutexPrivate::wakeUp() +{ + semaphore_signal(mach_semaphore); +} + + +QT_END_NAMESPACE + +#endif //QT_NO_THREAD diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index a9923c47a4..00f071ebef 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -57,50 +57,80 @@ #include #include #include +#include #if defined(Q_OS_MAC) # include #endif -#if defined(Q_OS_SYMBIAN) -# include -#endif - QT_BEGIN_NAMESPACE -class QMutexPrivate : public QMutexData { +class QMutexPrivate { public: - QMutexPrivate(QMutex::RecursionMode mode); ~QMutexPrivate(); + QMutexPrivate(QMutex::RecursionMode mode = QMutex::NonRecursive); bool wait(int timeout = -1); void wakeUp(); - // 1ms = 1000000ns - enum { MaximumSpinTimeThreshold = 1000000 }; - volatile qint64 maximumSpinTime; - volatile qint64 averageWaitTime; - Qt::HANDLE owner; - uint count; +#if !defined(Q_OS_LINUX) + // Conrol the lifetime of the privates + QAtomicInt refCount; + int id; + bool ref() { + Q_ASSERT(refCount >= 0); + int c; + do { + c = refCount; + if (c == 0) + return false; + } while (!refCount.testAndSetRelaxed(c, c + 1)); + Q_ASSERT(refCount >= 0); + return true; + } + void deref() { + Q_ASSERT(refCount >=0); + if (!refCount.deref()) + release(); + Q_ASSERT(refCount >=0); + } + void release(); + static QMutexPrivate *allocate(); + + QAtomicInt waiters; //number of thread waiting + QAtomicInt possiblyUnlocked; //bool saying that a timed wait timed out + enum { BigNumber = 0x100000 }; //Must be bigger than the possible number of waiters (number of threads) + void derefWaiters(int value); +#endif + + // handle recursive mutex + bool recursive; + + //platform specific stuff #if defined(Q_OS_MAC) semaphore_t mach_semaphore; -#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) && !defined(Q_OS_SYMBIAN) - volatile bool wakeup; +#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) + bool wakeup; pthread_mutex_t mutex; pthread_cond_t cond; #elif defined(Q_OS_WIN32) || defined(Q_OS_WINCE) HANDLE event; -#elif defined(Q_OS_SYMBIAN) - RSemaphore lock; #endif }; -inline QMutexData::QMutexData(QMutex::RecursionMode mode) - : recursive(mode == QMutex::Recursive) -{} +class QRecursiveMutexPrivate : public QMutexPrivate +{ +public: + QRecursiveMutexPrivate() + : QMutexPrivate(QMutex::Recursive), owner(0), count(0) {} + Qt::HANDLE owner; + uint count; + QMutex mutex; -inline QMutexData::~QMutexData() {} + bool lock(int timeout); + void unlock(); +}; QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index e692e19525..0bccad589d 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -46,142 +46,35 @@ #ifndef QT_NO_THREAD #include "qatomic.h" #include "qmutex_p.h" - #include #if defined(Q_OS_VXWORKS) && defined(wakeup) #undef wakeup #endif -#if defined(Q_OS_MAC) -# include -# include -#elif defined(Q_OS_LINUX) -# include -# include -# include -# include -#endif - QT_BEGIN_NAMESPACE -#if !defined(Q_OS_MAC) && !defined(Q_OS_LINUX) static void report_error(int code, const char *where, const char *what) { if (code != 0) qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code))); } -#endif - QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) - : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) + : recursive(mode == QMutex::Recursive), wakeup(false) { -#if defined(Q_OS_MAC) - kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); - if (r != KERN_SUCCESS) - qWarning("QMutex: failed to create semaphore, error %d", r); -#elif !defined(Q_OS_LINUX) - wakeup = false; report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); -#endif } QMutexPrivate::~QMutexPrivate() { -#if defined(Q_OS_MAC) - kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore); - if (r != KERN_SUCCESS) - qWarning("QMutex: failed to destroy semaphore, error %d", r); -#elif !defined(Q_OS_LINUX) report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy"); report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy"); -#endif -} - -#if defined(Q_OS_MAC) - -bool QMutexPrivate::wait(int timeout) -{ - if (contenders.fetchAndAddAcquire(1) == 0) { - // lock acquired without waiting - return true; - } - kern_return_t r; - if (timeout < 0) { - do { - r = semaphore_wait(mach_semaphore); - } while (r == KERN_ABORTED); - if (r != KERN_SUCCESS) - qWarning("QMutex: infinite wait failed, error %d", r); - } else { - mach_timespec_t ts; - ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; - ts.tv_sec = (timeout / 1000); - r = semaphore_timedwait(mach_semaphore, ts); - } - contenders.deref(); - return r == KERN_SUCCESS; -} - -void QMutexPrivate::wakeUp() -{ - semaphore_signal(mach_semaphore); -} - -#elif defined(Q_OS_LINUX) - -static inline int _q_futex(volatile int *addr, int op, int val, const struct timespec *timeout, int *addr2, int val2) -{ - return syscall(SYS_futex, addr, op, val, timeout, addr2, val2); } bool QMutexPrivate::wait(int timeout) { - struct timespec ts, *pts = 0; - QElapsedTimer timer; - if (timeout >= 0) { - ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; - ts.tv_sec = (timeout / 1000); - pts = &ts; - timer.start(); - } - while (contenders.fetchAndStoreAcquire(2) > 0) { - int r = _q_futex(&contenders._q_value, FUTEX_WAIT, 2, pts, 0, 0); - if (r != 0 && errno == ETIMEDOUT) - return false; - - if (pts) { - // recalculate the timeout - qint64 xtimeout = timeout * 1000 * 1000; - xtimeout -= timer.nsecsElapsed(); - if (xtimeout < 0) { - // timer expired after we returned - return false; - } - - ts.tv_sec = timeout / Q_INT64_C(1000) / 1000 / 1000; - ts.tv_nsec = timeout % (Q_INT64_C(1000) * 1000 * 1000); - } - } - return true; -} - -void QMutexPrivate::wakeUp() -{ - (void) contenders.fetchAndStoreRelease(0); - (void) _q_futex(&contenders._q_value, FUTEX_WAKE, 1, 0, 0, 0); -} - -#else // !Q_OS_MAC && !Q_OS_LINUX - -bool QMutexPrivate::wait(int timeout) -{ - if (contenders.fetchAndAddAcquire(1) == 0) { - // lock acquired without waiting - return true; - } report_error(pthread_mutex_lock(&mutex), "QMutex::lock", "mutex lock"); int errorCode = 0; while (!wakeup) { @@ -190,12 +83,10 @@ bool QMutexPrivate::wait(int timeout) } else { struct timeval tv; gettimeofday(&tv, 0); - timespec ti; ti.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000) * 1000; ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000); ti.tv_nsec %= 1000000000; - errorCode = pthread_cond_timedwait(&cond, &mutex, &ti); } if (errorCode) { @@ -207,10 +98,10 @@ bool QMutexPrivate::wait(int timeout) report_error(errorCode, "QMutex::lock()", "cv wait"); } } + bool ret = wakeup; wakeup = false; report_error(pthread_mutex_unlock(&mutex), "QMutex::lock", "mutex unlock"); - contenders.deref(); - return errorCode == 0; + return ret; } void QMutexPrivate::wakeUp() @@ -221,7 +112,6 @@ void QMutexPrivate::wakeUp() report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); } -#endif // !Q_OS_MAC && !Q_OS_LINUX QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp index 53ad8cfe89..f6670f6d1e 100644 --- a/src/corelib/thread/qmutex_win.cpp +++ b/src/corelib/thread/qmutex_win.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) - : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) + : recursive(mode) { event = CreateEvent(0, FALSE, FALSE, 0); if (!event) @@ -60,13 +60,7 @@ QMutexPrivate::~QMutexPrivate() bool QMutexPrivate::wait(int timeout) { - if (contenders.fetchAndAddAcquire(1) == 0) { - // lock acquired without waiting - return true; - } - bool returnValue = (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0); - contenders.deref(); - return returnValue; + return (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0); } void QMutexPrivate::wakeUp() diff --git a/src/corelib/thread/qorderedmutexlocker_p.h b/src/corelib/thread/qorderedmutexlocker_p.h index 8f01c1c056..e65a601369 100644 --- a/src/corelib/thread/qorderedmutexlocker_p.h +++ b/src/corelib/thread/qorderedmutexlocker_p.h @@ -79,8 +79,8 @@ public: void relock() { if (!locked) { - if (mtx1) mtx1->lockInline(); - if (mtx2) mtx2->lockInline(); + if (mtx1) mtx1->lock(); + if (mtx2) mtx2->lock(); locked = true; } } @@ -88,8 +88,8 @@ public: void unlock() { if (locked) { - if (mtx1) mtx1->unlockInline(); - if (mtx2) mtx2->unlockInline(); + if (mtx1) mtx1->unlock(); + if (mtx2) mtx2->unlock(); locked = false; } } @@ -100,10 +100,10 @@ public: if (mtx1 == mtx2) return false; if (mtx1 < mtx2) { - mtx2->lockInline(); + mtx2->lock(); return true; } - if (!mtx2->tryLockInline()) { + if (!mtx2->tryLock()) { mtx1->unlock(); mtx2->lock(); mtx1->lock(); diff --git a/src/corelib/thread/qwaitcondition_unix.cpp b/src/corelib/thread/qwaitcondition_unix.cpp index b946a9de24..dd85bf4023 100644 --- a/src/corelib/thread/qwaitcondition_unix.cpp +++ b/src/corelib/thread/qwaitcondition_unix.cpp @@ -146,7 +146,7 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time) { if (! mutex) return false; - if (mutex->d->recursive) { + if (mutex->isRecursive()) { qWarning("QWaitCondition: cannot wait on recursive mutexes"); return false; } diff --git a/src/corelib/thread/qwaitcondition_win.cpp b/src/corelib/thread/qwaitcondition_win.cpp index 8a8db97342..bf1ec5e5ba 100644 --- a/src/corelib/thread/qwaitcondition_win.cpp +++ b/src/corelib/thread/qwaitcondition_win.cpp @@ -164,7 +164,7 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time) { if (!mutex) return false; - if (mutex->d->recursive) { + if (mutex->isRecursive()) { qWarning("QWaitCondition::wait: Cannot wait on recursive mutexes"); return false; } diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri index 592ab1644b..309bf30d25 100644 --- a/src/corelib/thread/thread.pri +++ b/src/corelib/thread/thread.pri @@ -24,8 +24,7 @@ SOURCES += thread/qatomic.cpp \ thread/qthread.cpp \ thread/qthreadstorage.cpp -unix:!symbian:SOURCES += thread/qmutex_unix.cpp \ - thread/qthread_unix.cpp \ +unix:!symbian:SOURCES += thread/qthread_unix.cpp \ thread/qwaitcondition_unix.cpp symbian:SOURCES += thread/qmutex_symbian.cpp \ @@ -39,3 +38,9 @@ win32:SOURCES += thread/qmutex_win.cpp \ integrity:SOURCES += thread/qmutex_unix.cpp \ thread/qthread_unix.cpp \ thread/qwaitcondition_unix.cpp + +unix: { + macx-* { SOURCES += thread/qmutex_mac.cpp } + else:linux-* { SOURCES += thread/qmutex_linux.cpp } + else { SOURCES += thread/qmutex_unix.cpp } +} diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 9f21b72bfd..11ebd8a103 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -904,7 +904,7 @@ QByteArray &QByteArray::operator=(const char *str) x = const_cast(&shared_empty.ba); } else { int len = qstrlen(str); - if (d->ref != 1 || len > d->alloc || (len < d->size && len < d->alloc >> 1)) + if (d->ref != 1 || len > int(d->alloc) || (len < d->size && len < int(d->alloc) >> 1)) realloc(len); x = d; memcpy(x->data(), str, len + 1); // include null terminator @@ -1432,9 +1432,10 @@ void QByteArray::resize(int size) x->data()[size] = '\0'; d = x; } else { - if (d->ref != 1 || size > d->alloc || (!d->capacityReserved && size < d->size && size < d->alloc >> 1)) + if (d->ref != 1 || size > int(d->alloc) + || (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1)) realloc(qAllocMore(size, sizeof(Data))); - if (d->alloc >= size) { + if (int(d->alloc) >= size) { d->size = size; d->data()[size] = '\0'; } @@ -1563,7 +1564,7 @@ QByteArray &QByteArray::prepend(const char *str) QByteArray &QByteArray::prepend(const char *str, int len) { if (str) { - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(qAllocMore(d->size + len, sizeof(Data))); memmove(d->data()+len, d->data(), d->size); memcpy(d->data(), str, len); @@ -1581,7 +1582,7 @@ QByteArray &QByteArray::prepend(const char *str, int len) QByteArray &QByteArray::prepend(char ch) { - if (d->ref != 1 || d->size + 1 > d->alloc) + if (d->ref != 1 || d->size + 1 > int(d->alloc)) realloc(qAllocMore(d->size + 1, sizeof(Data))); memmove(d->data()+1, d->data(), d->size); d->data()[0] = ch; @@ -1619,7 +1620,7 @@ QByteArray &QByteArray::append(const QByteArray &ba) if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) { *this = ba; } else if (ba.d != &shared_null.ba) { - if (d->ref != 1 || d->size + ba.d->size > d->alloc) + if (d->ref != 1 || d->size + ba.d->size > int(d->alloc)) realloc(qAllocMore(d->size + ba.d->size, sizeof(Data))); memcpy(d->data() + d->size, ba.d->data(), ba.d->size); d->size += ba.d->size; @@ -1653,7 +1654,7 @@ QByteArray& QByteArray::append(const char *str) { if (str) { int len = qstrlen(str); - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(qAllocMore(d->size + len, sizeof(Data))); memcpy(d->data() + d->size, str, len + 1); // include null terminator d->size += len; @@ -1678,7 +1679,7 @@ QByteArray &QByteArray::append(const char *str, int len) if (len < 0) len = qstrlen(str); if (str && len) { - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(qAllocMore(d->size + len, sizeof(Data))); memcpy(d->data() + d->size, str, len); // include null terminator d->size += len; @@ -1695,7 +1696,7 @@ QByteArray &QByteArray::append(const char *str, int len) QByteArray& QByteArray::append(char ch) { - if (d->ref != 1 || d->size + 1 > d->alloc) + if (d->ref != 1 || d->size + 1 > int(d->alloc)) realloc(qAllocMore(d->size + 1, sizeof(Data))); d->data()[d->size++] = ch; d->data()[d->size] = '\0'; @@ -2204,7 +2205,7 @@ QByteArray QByteArray::repeated(int times) const QByteArray result; result.reserve(resultSize); - if (result.d->alloc != resultSize) + if (int(result.d->alloc) != resultSize) return QByteArray(); // not enough memory memcpy(result.d->data(), d->data(), d->size); diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index dbac302d05..b70dba4d55 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -133,10 +133,10 @@ struct QByteArrayData inline const char *data() const { return d + sizeof(qptrdiff) + offset; } }; -template struct QConstByteArrayData +template struct QConstByteArrayData { const QByteArrayData ba; - const char data[n]; + const char data[N + 1]; }; template struct QConstByteArrayDataPtr @@ -146,10 +146,10 @@ template struct QConstByteArrayDataPtr #if defined(Q_COMPILER_LAMBDA) -# define QByteArrayLiteral(str) ([]() { \ - enum { Size = sizeof(str) }; \ +# define QByteArrayLiteral(str) ([]() -> QConstByteArrayDataPtr { \ + enum { Size = sizeof(str) - 1 }; \ static const QConstByteArrayData qbytearray_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ QConstByteArrayDataPtr holder = { &qbytearray_literal }; \ return holder; }()) @@ -160,9 +160,9 @@ template struct QConstByteArrayDataPtr # define QByteArrayLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(str) }; \ + enum { Size = sizeof(str) - 1 }; \ static const QConstByteArrayData qbytearray_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ QConstByteArrayDataPtr holder = { &qbytearray_literal }; \ holder; }) #endif @@ -439,10 +439,10 @@ inline int QByteArray::capacity() const { return d->alloc; } inline void QByteArray::reserve(int asize) -{ if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacityReserved = true; } +{ if (d->ref != 1 || asize > int(d->alloc)) realloc(asize); d->capacityReserved = true; } inline void QByteArray::squeeze() -{ if (d->size < d->alloc) realloc(d->size); d->capacityReserved = false; } +{ if (d->size < int(d->alloc)) realloc(d->size); d->capacityReserved = false; } class Q_CORE_EXPORT QByteRef { QByteArray &a; diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 00261daa95..736bc63b11 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -317,8 +317,6 @@ QT_BEGIN_NAMESPACE \value Vertical \value Wide - \omitvalue Single - \sa decomposition() */ @@ -382,12 +380,6 @@ QT_BEGIN_NAMESPACE \value ByteOrderSwapped \value ParagraphSeparator \value LineSeparator - - \omitvalue null - \omitvalue replacement - \omitvalue byteOrderMark - \omitvalue byteOrderSwapped - \omitvalue nbsp */ /*! @@ -957,7 +949,7 @@ QString QChar::decomposition(uint ucs4) /*! Returns the tag defining the composition of the character. Returns - QChar::Single if no decomposition exists. + QChar::NoDecomposition if no decomposition exists. */ QChar::Decomposition QChar::decompositionTag() const { @@ -967,7 +959,7 @@ QChar::Decomposition QChar::decompositionTag() const /*! \overload Returns the tag defining the composition of the UCS-4-encoded character - specified by \a ucs4. Returns QChar::Single if no decomposition exists. + specified by \a ucs4. Returns QChar::NoDecomposition if no decomposition exists. */ QChar::Decomposition QChar::decompositionTag(uint ucs4) { @@ -1232,7 +1224,6 @@ ushort QChar::toCaseFolded(ushort ucs2) return ucs2 + qGetProp(ucs2)->caseFoldDiff; } - /*! \fn char QChar::toLatin1() const diff --git a/src/corelib/tools/qfreelist.cpp b/src/corelib/tools/qfreelist.cpp new file mode 100644 index 0000000000..bbbdb25e49 --- /dev/null +++ b/src/corelib/tools/qfreelist.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfreelist_p.h" + +QT_BEGIN_NAMESPACE + +// default sizes and offsets (no need to define these when customizing) +enum { + Offset0 = 0x00000000, + Offset1 = 0x00008000, + Offset2 = 0x00080000, + Offset3 = 0x00800000, + + Size0 = Offset1 - Offset0, + Size1 = Offset2 - Offset1, + Size2 = Offset3 - Offset2, + Size3 = QFreeListDefaultConstants::MaxIndex - Offset3 +}; + +const int QFreeListDefaultConstants::Sizes[QFreeListDefaultConstants::BlockCount] = { + Size0, + Size1, + Size2, + Size3 +}; + +QT_END_NAMESPACE + diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h new file mode 100644 index 0000000000..74ba3b587e --- /dev/null +++ b/src/corelib/tools/qfreelist_p.h @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFREELIST_P_H +#define QFREELIST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +/*! \internal + + Element in a QFreeList. ConstReferenceType and ReferenceType are used as + the return values for QFreeList::at() and QFreeList::operator[](). Contains + the real data storage (_t) and the id of the next free element (next). + + Note: the t() functions should be used to access the data, not _t. +*/ +template +struct QFreeListElement +{ + typedef const T &ConstReferenceType; + typedef T &ReferenceType; + + T _t; + int next; + + inline ConstReferenceType t() const { return _t; } + inline ReferenceType t() { return _t; } +}; + +/*! \internal + + Element in a QFreeList without a paylout. ConstReferenceType and + ReferenceType are void, the t() functions return void and are empty. +*/ +template <> +struct QFreeListElement +{ + typedef void ConstReferenceType; + typedef void ReferenceType; + + int next; + + inline void t() const { } + inline void t() { } +}; + +/*! \internal + + Defines default constants used by QFreeList: + + - The initial value returned by QFreeList::next() is zero. + + - QFreeList allows for up to 16777216 elements in QFreeList and uses the top + 8 bits to store a serial counter for ABA protection. + + - QFreeList will make a maximum of 4 allocations (blocks), with each + successive block larger than the previous. + + - Sizes static int[] array to define the size of each block. + + It is possible to define your own constants struct/class and give this to + QFreeList to customize/tune the behavior. +*/ +struct Q_AUTOTEST_EXPORT QFreeListDefaultConstants +{ + // used by QFreeList, make sure to define all of when customizing + enum { + InitialNextValue = 0, + IndexMask = 0x00ffffff, + SerialMask = ~IndexMask & ~0x80000000, + SerialCounter = IndexMask + 1, + MaxIndex = IndexMask, + BlockCount = 4, + }; + + static const int Sizes[BlockCount]; +}; + +/*! \internal + + This is a generic implementation of a lock-free free list. Use next() to + get the next free entry in the list, and release(id) when done with the id. + + This version is templated and allows having a payload of type T which can + be accessed using the id returned by next(). The payload is allocated and + deallocated automatically by the free list, but *NOT* when calling + next()/release(). Initialization should be done by code needing it after + next() returns. Likewise, cleanup() should happen before calling release(). + It is possible to have use 'void' as the payload type, in which case the + free list only contains indexes to the next free entry. + + The ConstantsType type defaults to QFreeListDefaultConstants above. You can + define your custom ConstantsType, see above for details on what needs to be + available. +*/ +template +class QFreeList +{ + typedef T ValueType; + typedef QFreeListElement ElementType; + typedef typename ElementType::ConstReferenceType ConstReferenceType; + typedef typename ElementType::ReferenceType ReferenceType; + + // return which block the index \a x falls in, and modify \a x to be the index into that block + static inline int blockfor(int &x) + { + for (int i = 0; i < ConstantsType::BlockCount; ++i) { + int size = ConstantsType::Sizes[i]; + if (x < size) + return i; + x -= size; + } + Q_ASSERT(false); + return -1; + } + + // allocate a block of the given \a size, initialized starting with the given \a offset + static inline ElementType *allocate(int offset, int size) + { + // qDebug("QFreeList: allocating %d elements (%ld bytes) with offset %d", size, size * sizeof(ElementType), offset); + ElementType *v = new ElementType[size]; + for (int i = 0; i < size; ++i) + v[i].next = offset + i + 1; + return v; + } + + // take the current serial number from \a o, increment it, and store it in \a n + static inline int incrementserial(int o, int n) + { + return (n & ConstantsType::IndexMask) | ((o + ConstantsType::SerialCounter) & ConstantsType::SerialMask); + } + + // the blocks + QAtomicPointer _v[ConstantsType::BlockCount]; + // the next free id + QAtomicInt _next; + + // QFreeList is not copyable + Q_DISABLE_COPY(QFreeList) + +public: + inline QFreeList(); + inline ~QFreeList(); + + // returns the payload for the given index \a x + inline ConstReferenceType at(int x) const; + inline ReferenceType operator[](int x); + + /* + Return the next free id. Use this id to access the payload (see above). + Call release(id) when done using the id. + */ + inline int next(); + inline void release(int id); +}; + +template +inline QFreeList::QFreeList() + : _next(ConstantsType::InitialNextValue) +{ } + +template +inline QFreeList::~QFreeList() +{ + for (int i = 0; i < ConstantsType::BlockCount; ++i) + delete [] static_cast(_v[i]); +} + +template +inline typename QFreeList::ConstReferenceType QFreeList::at(int x) const +{ + const int block = blockfor(x); + return _v[block][x].t(); +} + +template +inline typename QFreeList::ReferenceType QFreeList::operator[](int x) +{ + const int block = blockfor(x); + return _v[block][x].t(); +} + +template +inline int QFreeList::next() +{ + int id, newid, at; + ElementType *v; + do { + id = _next; // .loadAqcuire(); + + at = id & ConstantsType::IndexMask; + const int block = blockfor(at); + v = _v[block]; + + if (!v) { + v = allocate((id & ConstantsType::IndexMask) - at, ConstantsType::Sizes[block]); + if (!_v[block].testAndSetRelease(0, v)) { + // race with another thread lost + delete [] v; + v = _v[block]; + Q_ASSERT(v != 0); + } + } + + newid = v[at].next | (id & ~ConstantsType::IndexMask); + } while (!_next.testAndSetRelease(id, newid)); + // qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)", + // id & ConstantsType::IndexMask, + // newid & ConstantsType::IndexMask, + // (newid & ~ConstantsType::IndexMask) >> 24); + return id & ConstantsType::IndexMask; +} + +template +inline void QFreeList::release(int id) +{ + int at = id & ConstantsType::IndexMask; + const int block = blockfor(at); + ElementType *v = _v[block]; + + int x, newid; + do { + x = _next; // .loadAcquire(); + v[at].next = x & ConstantsType::IndexMask; + + newid = incrementserial(x, id); + } while (!_next.testAndSetRelease(x, newid)); + // qDebug("QFreeList::release(%d): _next now %d (was %d), serial %d", + // id & ConstantsType::IndexMask, + // newid & ConstantsType::IndexMask, + // x & ConstantsType::IndexMask, + // (newid & ~ConstantsType::IndexMask) >> 24); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QFREELIST_P_H diff --git a/src/corelib/tools/qharfbuzz.cpp b/src/corelib/tools/qharfbuzz.cpp index 68f780d9fd..324cd481ed 100644 --- a/src/corelib/tools/qharfbuzz.cpp +++ b/src/corelib/tools/qharfbuzz.cpp @@ -102,7 +102,7 @@ HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch) return QChar::mirroredChar(ch); } -void *HB_Library_Resolve(const char *library, int version, const char *symbol) +void (*HB_Library_Resolve(const char *library, int version, const char *symbol))() { #ifdef QT_NO_LIBRARY return 0; diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h index 9b404bdf0c..811b186e8b 100644 --- a/src/corelib/tools/qshareddata.h +++ b/src/corelib/tools/qshareddata.h @@ -279,6 +279,9 @@ namespace std { QT_BEGIN_NAMESPACE #endif +template Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer, Q_MOVABLE_TYPE); +template Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer, Q_MOVABLE_TYPE); + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 9e238193a3..9ce5eead8c 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -1267,10 +1267,10 @@ void QString::resize(int size) QString::free(d); d = x; } else { - if (d->ref != 1 || size > d->alloc || - (!d->capacityReserved && size < d->size && size < d->alloc >> 1)) + if (d->ref != 1 || size > int(d->alloc) || + (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1)) realloc(grow(size)); - if (d->alloc >= size) { + if (int(d->alloc) >= size) { d->size = size; d->data()[size] = '\0'; } @@ -1560,7 +1560,7 @@ QString &QString::append(const QString &str) if (d == &shared_null.str) { operator=(str); } else { - if (d->ref != 1 || d->size + str.d->size > d->alloc) + if (d->ref != 1 || d->size + str.d->size > int(d->alloc)) realloc(grow(d->size + str.d->size)); memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar)); d->size += str.d->size; @@ -1580,7 +1580,7 @@ QString &QString::append(const QLatin1String &str) const uchar *s = (const uchar *)str.latin1(); if (s) { int len = qstrlen((char *)s); - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(grow(d->size + len)); ushort *i = d->data() + d->size; while ((*i++ = *s++)) @@ -1623,7 +1623,7 @@ QString &QString::append(const QLatin1String &str) */ QString &QString::append(QChar ch) { - if (d->ref != 1 || d->size + 1 > d->alloc) + if (d->ref != 1 || d->size + 1 > int(d->alloc)) realloc(grow(d->size + 1)); d->data()[d->size++] = ch.unicode(); d->data()[d->size] = '\0'; @@ -3550,8 +3550,8 @@ static QByteArray toLatin1_helper(const QChar *data, int length) const __m128i questionMark = _mm_set1_epi16('?'); // SSE has no compare instruction for unsigned comparison. // The variables must be shiffted + 0x8000 to be compared - const __m128i signedBitOffset = _mm_set1_epi16(0x8000); - const __m128i thresholdMask = _mm_set1_epi16(0xff + 0x8000); + const __m128i signedBitOffset = _mm_set1_epi16(short(0x8000)); + const __m128i thresholdMask = _mm_set1_epi16(short(0xff + 0x8000)); for (int i = 0; i < chunkCount; ++i) { __m128i chunk1 = _mm_loadu_si128((__m128i*)src); // load src += 8; @@ -6152,7 +6152,7 @@ QString QString::repeated(int times) const QString result; result.reserve(resultSize); - if (result.d->alloc != resultSize) + if (int(result.d->alloc) != resultSize) return QString(); // not enough memory memcpy(result.d->data(), d->data(), d->size * sizeof(ushort)); diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index af3e3f3ff9..209994de16 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -97,36 +97,43 @@ template struct QConstStringDataPtr }; #if defined(Q_COMPILER_UNICODE_STRINGS) -template struct QConstStringData +template struct QConstStringData { const QStringData str; - const char16_t data[n]; + const char16_t data[N + 1]; }; -#define QT_QSTRING_UNICODE_MARKER u"" + +#define QT_UNICODE_LITERAL_II(str) u"" str #elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) // wchar_t is 2 bytes -template struct QConstStringData +template struct QConstStringData { const QStringData str; - const wchar_t data[n]; + const wchar_t data[N + 1]; }; -#define QT_QSTRING_UNICODE_MARKER L"" + +#if defined(Q_CC_MSVC) +# define QT_UNICODE_LITERAL_II(str) L##str +#else +# define QT_UNICODE_LITERAL_II(str) L"" str +#endif #else -template struct QConstStringData +template struct QConstStringData { const QStringData str; - const ushort data[n]; + const ushort data[N + 1]; }; #endif -#if defined(QT_QSTRING_UNICODE_MARKER) +#if defined(QT_UNICODE_LITERAL_II) +# define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str) # if defined(Q_COMPILER_LAMBDA) -# define QStringLiteral(str) ([]() { \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ +# define QStringLiteral(str) ([]() -> QConstStringDataPtr { \ + enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \ QConstStringDataPtr holder = { &qstring_literal }; \ return holder; }()) @@ -137,9 +144,9 @@ template struct QConstStringData # define QStringLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ + enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \ QConstStringDataPtr holder = { &qstring_literal }; \ holder; }) # endif diff --git a/src/corelib/tools/qstringbuilder.cpp b/src/corelib/tools/qstringbuilder.cpp index 4c6848498b..7c1bde4ac7 100644 --- a/src/corelib/tools/qstringbuilder.cpp +++ b/src/corelib/tools/qstringbuilder.cpp @@ -108,13 +108,12 @@ QT_BEGIN_NAMESPACE */ /*! \internal - Note: The len contains the ending \0 */ void QAbstractConcatenable::convertFromAscii(const char *a, int len, QChar *&out) { #ifndef QT_NO_TEXTCODEC if (QString::codecForCStrings && len) { - QString tmp = QString::fromAscii(a, len > 0 ? len - 1 : -1); + QString tmp = QString::fromAscii(a, len > 0 ? len : -1); memcpy(out, reinterpret_cast(tmp.constData()), sizeof(QChar) * tmp.size()); out += tmp.length(); return; @@ -126,7 +125,7 @@ void QAbstractConcatenable::convertFromAscii(const char *a, int len, QChar *&out while (*a) *out++ = QLatin1Char(*a++); } else { - for (int i = 0; i < len - 1; ++i) + for (int i = 0; i < len; ++i) *out++ = QLatin1Char(a[i]); } } diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index 6d998b62aa..30b81c42f4 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -294,7 +294,7 @@ template struct QConcatenable : private QAbstractConcatenable #ifndef QT_NO_CAST_FROM_ASCII static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out) { - QAbstractConcatenable::convertFromAscii(a, N, out); + QAbstractConcatenable::convertFromAscii(a, N - 1, out); } #endif static inline void appendTo(const char a[N], char *&out) @@ -313,7 +313,7 @@ template struct QConcatenable : private QAbstractConcaten #ifndef QT_NO_CAST_FROM_ASCII static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out) { - QAbstractConcatenable::convertFromAscii(a, N, out); + QAbstractConcatenable::convertFromAscii(a, N - 1, out); } #endif static inline void appendTo(const char a[N], char *&out) @@ -349,10 +349,9 @@ template <> struct QConcatenable : private QAbstractConcatenable enum { ExactSize = false }; static int size(const QByteArray &ba) { return ba.size(); } #ifndef QT_NO_CAST_FROM_ASCII - static inline void appendTo(const QByteArray &ba, QChar *&out) + static inline QT_ASCII_CAST_WARN void appendTo(const QByteArray &ba, QChar *&out) { - // adding 1 because convertFromAscii expects the size including the null-termination - QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size() + 1, out); + QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size(), out); } #endif static inline void appendTo(const QByteArray &ba, char *&out) @@ -364,6 +363,26 @@ template <> struct QConcatenable : private QAbstractConcatenable } }; +template struct QConcatenable > : private QAbstractConcatenable +{ + typedef QConstByteArrayDataPtr type; + typedef QByteArray ConvertTo; + enum { ExactSize = false }; + static int size(const type &) { return N; } +#ifndef QT_NO_CAST_FROM_ASCII + static inline QT_ASCII_CAST_WARN void appendTo(const type &a, QChar *&out) + { + QAbstractConcatenable::convertFromAscii(a.ptr->data, N, out); + } +#endif + static inline void appendTo(const type &ba, char *&out) + { + const char *a = ba.ptr->data; + while (*a) + *out++ = *a++; + } +}; + namespace QtStringBuilder { template struct ConvertToTypeHelper { typedef A ConvertTo; }; diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index f5b38eb1c0..13b597d513 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -13,6 +13,7 @@ HEADERS += \ tools/qdatetime.h \ tools/qdatetime_p.h \ tools/qeasingcurve.h \ + tools/qfreelist_p.h \ tools/qhash.h \ tools/qline.h \ tools/qlinkedlist.h \ @@ -61,6 +62,7 @@ SOURCES += \ tools/qdatetime.cpp \ tools/qeasingcurve.cpp \ tools/qelapsedtimer.cpp \ + tools/qfreelist.cpp \ tools/qhash.cpp \ tools/qline.cpp \ tools/qlinkedlist.cpp \ diff --git a/src/dbus/qdbus_symbols.cpp b/src/dbus/qdbus_symbols.cpp index fed18350bb..8e74b8b922 100644 --- a/src/dbus/qdbus_symbols.cpp +++ b/src/dbus/qdbus_symbols.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE -void *qdbus_resolve_me(const char *name); +void (*qdbus_resolve_me(const char *name))(); #if !defined QT_LINKED_LIBDBUS @@ -95,20 +95,19 @@ bool qdbus_loadLibDBus() return false; } -void *qdbus_resolve_conditionally(const char *name) +void (*qdbus_resolve_conditionally(const char *name))() { if (qdbus_loadLibDBus()) return qdbus_libdbus->resolve(name); return 0; } -void *qdbus_resolve_me(const char *name) +void (*qdbus_resolve_me(const char *name))() { - void *ptr = 0; if (!qdbus_loadLibDBus()) qFatal("Cannot find libdbus-1 in your system to resolve symbol '%s'.", name); - ptr = qdbus_libdbus->resolve(name); + QFunctionPointer ptr = qdbus_libdbus->resolve(name); if (!ptr) qFatal("Cannot resolve '%s' in your libdbus-1.", name); diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h index a59c08a8ab..8178e2ecf3 100644 --- a/src/dbus/qdbus_symbols_p.h +++ b/src/dbus/qdbus_symbols_p.h @@ -63,8 +63,8 @@ QT_BEGIN_NAMESPACE #if !defined QT_LINKED_LIBDBUS -void *qdbus_resolve_conditionally(const char *name); // doesn't print a warning -void *qdbus_resolve_me(const char *name); // prints a warning +void (*qdbus_resolve_conditionally(const char *name))(); // doesn't print a warning +void (*qdbus_resolve_me(const char *name))(); // prints a warning bool qdbus_loadLibDBus(); # define DEFINEFUNC(ret, func, args, argcall, funcret) \ diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index d12642d632..8daf2300b7 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -125,6 +125,11 @@ private: MethodScriptable = 0x40 }; + enum MetaObjectFlags { + DynamicMetaObject = 0x01, + RequiresVariantMetaObject = 0x02 + }; + QMap methods; QMap properties; @@ -152,6 +157,8 @@ struct QDBusMetaObjectPrivate int methodCount, methodData; int propertyCount, propertyData; int enumeratorCount, enumeratorData; + int constructorCount, constructorData; // since revision 2 + int flags; // since revision 3 // this is specific for QDBusMetaObject: int propertyDBusData; @@ -416,7 +423,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) idata.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int)); QDBusMetaObjectPrivate *header = reinterpret_cast(idata.data()); - header->revision = 1; + header->revision = 3; header->className = 0; header->classInfoCount = 0; header->classInfoData = 0; @@ -426,6 +433,9 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) header->propertyData = header->methodData + header->methodCount * 5; header->enumeratorCount = 0; header->enumeratorData = 0; + header->constructorCount = 0; + header->constructorData = 0; + header->flags = RequiresVariantMetaObject; header->propertyDBusData = header->propertyData + header->propertyCount * 3; header->methodDBusData = header->propertyDBusData + header->propertyCount * intsPerProperty; diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 7848bc96f3..d854b1765b 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -97,8 +97,10 @@ static QDataStream &operator<<(QDataStream &s, const BMP_FILEHDR &bf) const int BMP_OLD = 12; // old Windows/OS2 BMP size -const int BMP_WIN = 40; // new Windows BMP size +const int BMP_WIN = 40; // Windows BMP v3 size const int BMP_OS2 = 64; // new OS/2 BMP size +const int BMP_WIN4 = 108; // Windows BMP v4 size +const int BMP_WIN5 = 124; // Windows BMP v5 size const int BMP_RGB = 0; // no compression const int BMP_RLE8 = 1; // run-length encoded, 8 bits @@ -109,7 +111,7 @@ const int BMP_BITFIELDS = 3; // RGB values encoded in dat static QDataStream &operator>>(QDataStream &s, BMP_INFOHDR &bi) { s >> bi.biSize; - if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2) { + if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2 || bi.biSize == BMP_WIN4 || bi.biSize == BMP_WIN5) { s >> bi.biWidth >> bi.biHeight >> bi.biPlanes >> bi.biBitCount; s >> bi.biCompression >> bi.biSizeImage; s >> bi.biXPelsPerMeter >> bi.biYPelsPerMeter; @@ -255,7 +257,57 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int image.setDotsPerMeterY(bi.biYPelsPerMeter); if (!d->isSequential()) - d->seek(startpos + BMP_FILEHDR_SIZE + bi.biSize); // goto start of colormap + d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap + + if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) { + Q_ASSERT(ncols == 0); + + if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) + return false; + if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask)) + return false; + if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask)) + return false; + + // Read BMP v4+ header + if (bi.biSize >= BMP_WIN4) { + int alpha_mask = 0; + int CSType = 0; + int gamma_red = 0; + int gamma_green = 0; + int gamma_blue = 0; + int endpoints[9]; + + if (d->read((char *)&alpha_mask, sizeof(alpha_mask)) != sizeof(alpha_mask)) + return false; + if (d->read((char *)&CSType, sizeof(CSType)) != sizeof(CSType)) + return false; + if (d->read((char *)&endpoints, sizeof(endpoints)) != sizeof(endpoints)) + return false; + if (d->read((char *)&gamma_red, sizeof(gamma_red)) != sizeof(gamma_red)) + return false; + if (d->read((char *)&gamma_green, sizeof(gamma_green)) != sizeof(gamma_green)) + return false; + if (d->read((char *)&gamma_blue, sizeof(gamma_blue)) != sizeof(gamma_blue)) + return false; + + if (bi.biSize == BMP_WIN5) { + qint32 intent = 0; + qint32 profileData = 0; + qint32 profileSize = 0; + qint32 reserved = 0; + + if (d->read((char *)&intent, sizeof(intent)) != sizeof(intent)) + return false; + if (d->read((char *)&profileData, sizeof(profileData)) != sizeof(profileData)) + return false; + if (d->read((char *)&profileSize, sizeof(profileSize)) != sizeof(profileSize)) + return false; + if (d->read((char *)&reserved, sizeof(reserved)) != sizeof(reserved) || reserved != 0) + return false; + } + } + } if (ncols > 0) { // read color table uchar rgb[4]; @@ -268,12 +320,6 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int return false; } } else if (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32)) { - if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) - return false; - if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask)) - return false; - if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask)) - return false; red_shift = calc_shift(red_mask); red_scale = 256 / ((red_mask >> red_shift) + 1); green_shift = calc_shift(green_mask); diff --git a/src/gui/image/qtiffhandler.cpp b/src/gui/image/qtiffhandler.cpp index c753b83294..4dc9775d46 100644 --- a/src/gui/image/qtiffhandler.cpp +++ b/src/gui/image/qtiffhandler.cpp @@ -236,14 +236,14 @@ bool QTiffHandler::read(QImage *image) } } else { // create the color table - uint16 *redTable = static_cast(qMalloc(tableSize * sizeof(uint16))); - uint16 *greenTable = static_cast(qMalloc(tableSize * sizeof(uint16))); - uint16 *blueTable = static_cast(qMalloc(tableSize * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { + uint16 *redTable = 0; + uint16 *greenTable = 0; + uint16 *blueTable = 0; + if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { TIFFClose(tiff); return false; } - if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { + if (!redTable || !greenTable || !blueTable) { TIFFClose(tiff); return false; } @@ -500,6 +500,9 @@ bool QTiffHandler::write(const QImage &image) uint16 *greenTable = static_cast(qMalloc(256 * sizeof(uint16))); uint16 *blueTable = static_cast(qMalloc(256 * sizeof(uint16))); if (!redTable || !greenTable || !blueTable) { + qFree(redTable); + qFree(greenTable); + qFree(blueTable); TIFFClose(tiff); return false; } diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp index 837bd519b8..cef92af66b 100644 --- a/src/gui/math3d/qmatrix4x4.cpp +++ b/src/gui/math3d/qmatrix4x4.cpp @@ -55,6 +55,20 @@ QT_BEGIN_NAMESPACE \since 4.6 \ingroup painting-3D + The QMatrix4x4 class in general is treated as a row-major matrix, in that the + constructors and operator() functions take data in row-major format, as is + familiar in C-style usage. + + Internally the data is stored as column-major format, so as to be optimal for + passing to OpenGL functions, which expect column-major data. + + When using these functions be aware that they return data in \bold{column-major} + format: + \list + \o data() + \o constData() + \endlist + \sa QVector3D, QGenericMatrix */ @@ -1725,6 +1739,7 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const \fn const qreal *QMatrix4x4::data() const Returns a constant pointer to the raw data of this matrix. + This raw data is stored in column-major format. \sa constData() */ @@ -1733,6 +1748,7 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const \fn const qreal *QMatrix4x4::constData() const Returns a constant pointer to the raw data of this matrix. + This raw data is stored in column-major format. \sa data() */ diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 908fdf1183..566b4d5f61 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3005,7 +3005,7 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) ensureState(); QFontEngine *fontEngine = textItem->fontEngine(); - if (!supportsTransformations(fontEngine)) { + if (shouldDrawCachedGlyphs(fontEngine->fontDef.pixelSize, state()->matrix)) { drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, fontEngine); } else { @@ -3355,10 +3355,7 @@ bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransfo #endif return true; - if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64) - return true; - - return false; + return !shouldDrawCachedGlyphs(pixelSize, m); } /*! diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 9427dd5105..5ef6900cc8 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -53,6 +53,10 @@ QT_BEGIN_NAMESPACE +#if !defined(QT_MAX_CACHED_GLYPH_SIZE) +# define QT_MAX_CACHED_GLYPH_SIZE 64 +#endif + /******************************************************************************* * * class QVectorPath @@ -1096,4 +1100,10 @@ bool QPaintEngineEx::supportsTransformations(qreal pixelSize, const QTransform & return false; } +bool QPaintEngineEx::shouldDrawCachedGlyphs(qreal pixelSize, const QTransform &m) const +{ + return (pixelSize * pixelSize * qAbs(m.determinant())) < + QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE; +} + QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 604a43133f..d9ab506c94 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -228,6 +228,7 @@ public: }; virtual uint flags() const {return 0;} virtual bool supportsTransformations(qreal pixelSize, const QTransform &m) const; + virtual bool shouldDrawCachedGlyphs(qreal pixelSize, const QTransform &m) const; protected: QPaintEngineEx(QPaintEngineExPrivate &data); diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 6ae410cada..c53e841cf4 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -155,6 +155,7 @@ public: struct FaceId { FaceId() : index(0), encoding(0) {} QByteArray filename; + QByteArray uuid; int index; int encoding; }; @@ -303,7 +304,7 @@ inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId inline uint qHash(const QFontEngine::FaceId &f) { - return qHash((f.index << 16) + f.encoding) + qHash(f.filename); + return qHash((f.index << 16) + f.encoding) + qHash(f.filename + f.uuid); } diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index 4c65ad5de0..26b6a8aad7 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -139,7 +139,7 @@ QRawFont::QRawFont() \note The referenced file must contain a TrueType or OpenType font. */ QRawFont::QRawFont(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) : d(new QRawFontPrivate) { @@ -154,7 +154,7 @@ QRawFont::QRawFont(const QString &fileName, \note The data must contain a TrueType or OpenType font. */ QRawFont::QRawFont(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) : d(new QRawFontPrivate) { @@ -204,7 +204,7 @@ bool QRawFont::isValid() const \sa loadFromData() */ void QRawFont::loadFromFile(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { QFile file(fileName); @@ -222,7 +222,7 @@ void QRawFont::loadFromFile(const QString &fileName, \sa loadFromFile() */ void QRawFont::loadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { detach(); diff --git a/src/gui/text/qrawfont.h b/src/gui/text/qrawfont.h index e94bd99b8c..f7d7494f0b 100644 --- a/src/gui/text/qrawfont.h +++ b/src/gui/text/qrawfont.h @@ -70,10 +70,10 @@ public: QRawFont(); QRawFont(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); QRawFont(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); QRawFont(const QRawFont &other); ~QRawFont(); @@ -117,11 +117,11 @@ public: qreal unitsPerEm() const; void loadFromFile(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference); void loadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference); bool supportsCharacter(quint32 ucs4) const; diff --git a/src/gui/text/qrawfont_ft.cpp b/src/gui/text/qrawfont_ft.cpp index db60459176..1666df3fdf 100644 --- a/src/gui/text/qrawfont_ft.cpp +++ b/src/gui/text/qrawfont_ft.cpp @@ -45,6 +45,7 @@ #include "qrawfont_p.h" #include "qfontengine_ft_p.h" +#include "quuid.h" #if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG) # include "qfontengine_x11_p.h" @@ -87,6 +88,7 @@ public: FaceId faceId; faceId.filename = ""; faceId.index = 0; + faceId.uuid = QUuid::createUuid().toByteArray(); return init(faceId, true, Format_None, fontData); } @@ -98,7 +100,7 @@ void QRawFontPrivate::platformCleanUp() // Font engine handles all resources } -void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize, +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { Q_ASSERT(fontEngine == 0); diff --git a/src/gui/text/qrawfont_p.h b/src/gui/text/qrawfont_p.h index 56ea6a031d..4a4ed56223 100644 --- a/src/gui/text/qrawfont_p.h +++ b/src/gui/text/qrawfont_p.h @@ -99,7 +99,7 @@ public: void cleanUp(); void platformCleanUp(); void platformLoadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference); static QRawFontPrivate *get(const QRawFont &font) { return font.d.data(); } diff --git a/src/gui/text/qrawfont_qpa.cpp b/src/gui/text/qrawfont_qpa.cpp index b80b64cbaf..47815baf06 100644 --- a/src/gui/text/qrawfont_qpa.cpp +++ b/src/gui/text/qrawfont_qpa.cpp @@ -53,7 +53,7 @@ void QRawFontPrivate::platformCleanUp() { } -void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize, +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { Q_ASSERT(fontEngine == 0); diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index 3d7e597f23..689fd4379b 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1817,6 +1817,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) bool isGettingInput = !e->commitString().isEmpty() || e->preeditString() != cursor.block().layout()->preeditAreaText() || e->replacementLength() > 0; + bool forceSelectionChanged = false; cursor.beginEditBlock(); if (isGettingInput) { @@ -1840,6 +1841,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor); q->ensureCursorVisible(); repaintOldAndNewSelection(oldCursor); + forceSelectionChanged = true; } } @@ -1874,6 +1876,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) cursor_d->setX(); if (oldPreeditCursor != preeditCursor) emit q->microFocusChanged(); + selectionChanged(forceSelectionChanged); } QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 5cc3d73fb9..0d3aa0b585 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1632,7 +1632,7 @@ bool QTextEngine::isRightToLeft() const int QTextEngine::findItem(int strPos) const { itemize(); - int left = 0; + int left = 1; int right = layoutData->items.size()-1; while(left <= right) { int middle = ((right-left)/2)+left; diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index b32bea8b7a..43251a8829 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -131,6 +131,69 @@ QT_BEGIN_NAMESPACE \omitvalue Valid */ + +/*! + \fn void QIntValidator::topChanged(int top) + + This signal is emitted after the top property changed. + + \sa QIntValidator::top(), QIntValidator::setTop(), QIntValidator::bottom(), QIntValidator::setBottom() + \internal +*/ + +/*! + \fn void QIntValidator::bottomChanged(int bottom) + + This signal is emitted after the bottom property changed. + + \sa QIntValidator::top(), QIntValidator::setTop(), QIntValidator::bottom(), QIntValidator::setBottom() + \internal +*/ + +/*! + \fn void QDoubleValidator::topChanged(int top) + + This signal is emitted after the top property changed. + + \sa QDoubleValidator::top(), QDoubleValidator::setTop(), QDoubleValidator::bottom(), QDoubleValidator::setBottom() + \internal +*/ + +/*! + \fn void QDoubleValidator::bottomChanged(int bottom) + + This signal is emitted after the bottom property changed. + + \sa QDoubleValidator::top(), QDoubleValidator::setTop(), QDoubleValidator::bottom(), QDoubleValidator::setBottom() + \internal +*/ + +/*! + \fn void QDoubleValidator::decimalsChanged(int decimals) + + This signal is emitted after the decimals property changed. + + \internal +*/ + +/*! + \fn void QDoubleValidator::notationChanged(QDoubleValidator::Notation notation) + + This signal is emitted after the notation property changed. + + QDoubleValidator::Notation is not a registered metatype, so for queued connections, + you will have to register it with Q_DECLARE_METATYPE() and qRegisterMetaType(). + + \internal +*/ + +/*! + \fn void QRegExpValidator::regExpChanged(const QRegExp ®Exp) + + This signal is emitted after the regExp property changed. + \internal +*/ + class QValidatorPrivate : public QObjectPrivate{ Q_DECLARE_PUBLIC(QValidator) public: @@ -436,8 +499,15 @@ void QIntValidator::fixup(QString &input) const void QIntValidator::setRange(int bottom, int top) { - b = bottom; - t = top; + if (b != bottom) { + b = bottom; + emit bottomChanged(b); + } + + if (t != top) { + t = top; + emit topChanged(t); + } } @@ -710,9 +780,20 @@ QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QL void QDoubleValidator::setRange(double minimum, double maximum, int decimals) { - b = minimum; - t = maximum; - dec = decimals; + if (b != minimum) { + b = minimum; + emit bottomChanged(b); + } + + if (t != maximum) { + t = maximum; + emit topChanged(t); + } + + if (dec != decimals) { + dec = decimals; + emit decimalsChanged(dec); + } } /*! @@ -771,7 +852,10 @@ void QDoubleValidator::setDecimals(int decimals) void QDoubleValidator::setNotation(Notation newNotation) { Q_D(QDoubleValidator); - d->notation = newNotation; + if (d->notation != newNotation) { + d->notation = newNotation; + emit notationChanged(d->notation); + } } QDoubleValidator::Notation QDoubleValidator::notation() const @@ -915,7 +999,10 @@ QValidator::State QRegExpValidator::validate(QString &input, int& pos) const void QRegExpValidator::setRegExp(const QRegExp& rx) { - r = rx; + if (r != rx) { + r = rx; + emit regExpChanged(r); + } } #endif diff --git a/src/gui/util/qvalidator.h b/src/gui/util/qvalidator.h index 70f656e6a8..cb0436cc3e 100644 --- a/src/gui/util/qvalidator.h +++ b/src/gui/util/qvalidator.h @@ -96,8 +96,8 @@ private: class Q_GUI_EXPORT QIntValidator : public QValidator { Q_OBJECT - Q_PROPERTY(int bottom READ bottom WRITE setBottom) - Q_PROPERTY(int top READ top WRITE setTop) + Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY bottomChanged) + Q_PROPERTY(int top READ top WRITE setTop NOTIFY topChanged) public: explicit QIntValidator(QObject * parent = 0); @@ -113,7 +113,9 @@ public: int bottom() const { return b; } int top() const { return t; } - +Q_SIGNALS: + void bottomChanged(int bottom); + void topChanged(int top); #ifdef QT3_SUPPORT public: QT3_SUPPORT_CONSTRUCTOR QIntValidator(QObject * parent, const char *name); @@ -134,11 +136,11 @@ class QDoubleValidatorPrivate; class Q_GUI_EXPORT QDoubleValidator : public QValidator { Q_OBJECT - Q_PROPERTY(double bottom READ bottom WRITE setBottom) - Q_PROPERTY(double top READ top WRITE setTop) - Q_PROPERTY(int decimals READ decimals WRITE setDecimals) + Q_PROPERTY(double bottom READ bottom WRITE setBottom NOTIFY bottomChanged) + Q_PROPERTY(double top READ top WRITE setTop NOTIFY topChanged) + Q_PROPERTY(int decimals READ decimals WRITE setDecimals NOTIFY decimalsChanged) Q_ENUMS(Notation) - Q_PROPERTY(Notation notation READ notation WRITE setNotation) + Q_PROPERTY(Notation notation READ notation WRITE setNotation NOTIFY notationChanged) public: explicit QDoubleValidator(QObject * parent = 0); @@ -149,7 +151,6 @@ public: StandardNotation, ScientificNotation }; - QValidator::State validate(QString &, int &) const; virtual void setRange(double bottom, double top, int decimals = 0); @@ -163,6 +164,12 @@ public: int decimals() const { return dec; } Notation notation() const; +Q_SIGNALS: + void bottomChanged(double bottom); + void topChanged(double top); + void decimalsChanged(int decimals); + void notationChanged(QDoubleValidator::Notation notation); + #ifdef QT3_SUPPORT public: QT3_SUPPORT_CONSTRUCTOR QDoubleValidator(QObject * parent, const char *name); @@ -182,7 +189,7 @@ private: class Q_GUI_EXPORT QRegExpValidator : public QValidator { Q_OBJECT - Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp) + Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp NOTIFY regExpChanged) public: explicit QRegExpValidator(QObject *parent = 0); @@ -194,6 +201,8 @@ public: void setRegExp(const QRegExp& rx); const QRegExp& regExp() const { return r; } // ### make inline for 5.0 +Q_SIGNALS: + void regExpChanged(const QRegExp& regExp); #ifdef QT3_SUPPORT public: QT3_SUPPORT_CONSTRUCTOR QRegExpValidator(QObject *parent, const char *name); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index ab103ba836..58b9002222 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -97,10 +97,6 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled; extern bool qt_applefontsmoothing_enabled; #endif -#if !defined(QT_MAX_CACHED_GLYPH_SIZE) -# define QT_MAX_CACHED_GLYPH_SIZE 64 -#endif - Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); ////////////////////////////////// Private Methods ////////////////////////////////////////// @@ -1441,8 +1437,7 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) // don't try to cache huge fonts or vastly transformed fonts QFontEngine *fontEngine = textItem->fontEngine(); const qreal pixelSize = fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(det) < QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE || - det < 0.25f || det > 4.f) { + if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) { QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat) : d->glyphCacheType; @@ -1500,8 +1495,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem // don't try to cache huge fonts or vastly transformed fonts const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(det) >= QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE || - det < 0.25f || det > 4.f) + if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) drawCached = false; QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index 1fd9e373ed..c35488da02 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -347,13 +347,13 @@ static void find_trans_colors() QGLFormat UNIX/GLX-specific code *****************************************************************************/ -void* qglx_getProcAddress(const char* procName) +void (*qglx_getProcAddress(const char* procName))() { // On systems where the GL driver is pluggable (like Mesa), we have to use // the glXGetProcAddressARB extension to resolve other function pointers as // the symbols wont be in the GL library, but rather in a plugin loaded by // the GL library. - typedef void* (*qt_glXGetProcAddressARB)(const char *); + typedef void (*(*qt_glXGetProcAddressARB)(const char *))(); static qt_glXGetProcAddressARB glXGetProcAddressARB = 0; static bool triedResolvingGlxGetProcAddress = false; if (!triedResolvingGlxGetProcAddress) { @@ -378,7 +378,7 @@ void* qglx_getProcAddress(const char* procName) } } - void *procAddress = 0; + void (*procAddress)() = 0; if (glXGetProcAddressARB) procAddress = glXGetProcAddressARB(procName); @@ -387,7 +387,7 @@ void* qglx_getProcAddress(const char* procName) if (!procAddress) { void *handle = dlopen(NULL, RTLD_LAZY); if (handle) { - procAddress = dlsym(handle, procName); + procAddress = (void (*)())dlsym(handle, procName); dlclose(handle); } } diff --git a/src/opengl/qglpixelbuffer_x11.cpp b/src/opengl/qglpixelbuffer_x11.cpp index 9e8beba311..fcd7b521bb 100644 --- a/src/opengl/qglpixelbuffer_x11.cpp +++ b/src/opengl/qglpixelbuffer_x11.cpp @@ -93,7 +93,7 @@ static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0; #define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib #define glXMakeContextCurrent qt_glXMakeContextCurrent -extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp +extern void (*qglx_getProcAddress(const char* procName))(); // in qgl_x11.cpp static bool qt_resolve_pbuffer_extensions() { diff --git a/src/plugins/platforms/xlib/qxlibstatic.cpp b/src/plugins/platforms/xlib/qxlibstatic.cpp index ee4c463b94..3ba0eb4c32 100644 --- a/src/plugins/platforms/xlib/qxlibstatic.cpp +++ b/src/plugins/platforms/xlib/qxlibstatic.cpp @@ -218,8 +218,8 @@ static const char * x11_atomnames = { \c XFIXES_MAJOR - it is a part of soname and may differ from the Xfixes version. */ -static void* qt_load_library_runtime(const char *library, int vernum, - int highestVernum, const char *symbol) +static QFunctionPointer qt_load_library_runtime(const char *library, int vernum, + int highestVernum, const char *symbol) { QList versions; // we try to load in the following order: @@ -234,7 +234,7 @@ static void* qt_load_library_runtime(const char *library, int vernum, Q_FOREACH(int version, versions) { QLatin1String libName(library); QLibrary xfixesLib(libName, version); - void *ptr = xfixesLib.resolve(symbol); + QFunctionPointer ptr = xfixesLib.resolve(symbol); if (ptr) return ptr; } diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp index f6c401842f..5b0406f4b0 100644 --- a/src/sql/models/qsqlrelationaltablemodel.cpp +++ b/src/sql/models/qsqlrelationaltablemodel.cpp @@ -119,6 +119,8 @@ QT_BEGIN_NAMESPACE returns false. */ +class QRelatedTableModel; + struct QRelation { public: @@ -135,7 +137,7 @@ struct QRelation bool isValid(); QSqlRelation rel; - QSqlTableModel *model; + QRelatedTableModel *model; QHash dictionary;//maps keys to display values private: @@ -143,6 +145,15 @@ struct QRelation bool m_dictInitialized; }; +class QRelatedTableModel : public QSqlTableModel +{ +public: + QRelatedTableModel(QRelation *rel, QObject *parent = 0, QSqlDatabase db = QSqlDatabase()); + bool select(); +private: + bool firstSelect; + QRelation *relation; +}; /* A QRelation must be initialized before it is considered valid. Note: population of the model and dictionary are kept separate @@ -162,7 +173,7 @@ void QRelation::populateModel() Q_ASSERT(m_parent != NULL); if (!model) { - model = new QSqlTableModel(m_parent, m_parent->database()); + model = new QRelatedTableModel(this, m_parent, m_parent->database()); model->setTable(rel.tableName()); model->select(); } @@ -219,6 +230,27 @@ bool QRelation::isValid() return (rel.isValid() && m_parent != NULL); } + + +QRelatedTableModel::QRelatedTableModel(QRelation *rel, QObject *parent, QSqlDatabase db) : + QSqlTableModel(parent, db), firstSelect(true), relation(rel) +{ +} + +bool QRelatedTableModel::select() +{ + if (firstSelect) { + firstSelect = false; + return QSqlTableModel::select(); + } + relation->clearDictionary(); + bool res = QSqlTableModel::select(); + if (res) + relation->populateDictionary(); + return res; +} + + class QSqlRelationalTableModelPrivate: public QSqlTableModelPrivate { Q_DECLARE_PUBLIC(QSqlRelationalTableModel) diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro index 435036e0c8..a017d33b4a 100644 --- a/src/testlib/testlib.pro +++ b/src/testlib/testlib.pro @@ -88,7 +88,7 @@ qpa:mac: { load(qt_module_config) -HEADERS += $$QT_SOURCE_TREE/src/testlib/qttestlibversion.h +HEADERS += $$QT_SOURCE_TREE/src/testlib/qttestversion.h QMAKE_TARGET_PRODUCT = QTestLib QMAKE_TARGET_DESCRIPTION = Qt \ diff --git a/src/widgets/platforms/mac/qrawfont_mac.cpp b/src/widgets/platforms/mac/qrawfont_mac.cpp index df68eb7e7a..40c719a1af 100644 --- a/src/widgets/platforms/mac/qrawfont_mac.cpp +++ b/src/widgets/platforms/mac/qrawfont_mac.cpp @@ -55,7 +55,7 @@ void QRawFontPrivate::platformCleanUp() extern int qt_defaultDpi(); void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { // Mac OS X ignores it diff --git a/src/widgets/platforms/win/qrawfont_win.cpp b/src/widgets/platforms/win/qrawfont_win.cpp index 6c62673b54..d8aa557975 100644 --- a/src/widgets/platforms/win/qrawfont_win.cpp +++ b/src/widgets/platforms/win/qrawfont_win.cpp @@ -529,7 +529,8 @@ void QRawFontPrivate::platformCleanUp() { if (fontHandle != NULL) { if (ptrRemoveFontMemResourceEx == NULL) { - void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + QFunctionPointer func = + QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); ptrRemoveFontMemResourceEx = reinterpret_cast(func); } @@ -545,7 +546,7 @@ void QRawFontPrivate::platformCleanUp() } void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { QByteArray fontData(_fontData); @@ -572,7 +573,8 @@ void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData, } if (ptrAddFontMemResourceEx == NULL || ptrRemoveFontMemResourceEx == NULL) { - void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + QFunctionPointer func = + QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); ptrRemoveFontMemResourceEx = reinterpret_cast(func); diff --git a/src/widgets/platforms/x11/qkeymapper_x11.cpp b/src/widgets/platforms/x11/qkeymapper_x11.cpp index e243716f6a..455840f8b2 100644 --- a/src/widgets/platforms/x11/qkeymapper_x11.cpp +++ b/src/widgets/platforms/x11/qkeymapper_x11.cpp @@ -513,7 +513,7 @@ void QKeyMapperPrivate::clearMappings() // ### ??? // if (keyboardLayoutName.isEmpty()) - // qWarning("Qt: unable to determine keyboard layout, please talk to qt-bugs@trolltech.com"); ? + // qWarning("Qt: unable to determine keyboard layout, please talk to qt-info@nokia.com"); ? keyboardInputLocale = q_getKeyboardLocale(layoutName, variantName); keyboardInputDirection = keyboardInputLocale.textDirection(); diff --git a/src/widgets/widgets/qtabwidget.h b/src/widgets/widgets/qtabwidget.h index 447560f332..899b7a5dba 100644 --- a/src/widgets/widgets/qtabwidget.h +++ b/src/widgets/widgets/qtabwidget.h @@ -148,6 +148,8 @@ public: void clear(); + QTabBar* tabBar() const; + public Q_SLOTS: void setCurrentIndex(int index); void setCurrentWidget(QWidget *widget); @@ -165,7 +167,6 @@ protected: void keyPressEvent(QKeyEvent *); void paintEvent(QPaintEvent *); void setTabBar(QTabBar *); - QTabBar* tabBar() const; void changeEvent(QEvent *); bool event(QEvent *); void initStyleOption(QStyleOptionTabWidgetFrame *option) const; diff --git a/src/winmain/winmain.pro b/src/winmain/winmain.pro index b353e8e382..6630d86326 100644 --- a/src/winmain/winmain.pro +++ b/src/winmain/winmain.pro @@ -1,7 +1,6 @@ # Additional Qt project file for qtmain lib on Windows TEMPLATE = lib TARGET = qtmain -DESTDIR = $$QMAKE_LIBDIR_QT QT = CONFIG += staticlib warn_on @@ -17,5 +16,6 @@ win32 { !win32:error("$$_FILE_ is intended only for Windows!") load(qt_module_config) +DESTDIR = $$QMAKE_LIBDIR_QT wince*:QMAKE_POST_LINK = diff --git a/tests/auto/corelib.pro b/tests/auto/corelib.pro index 95a16f67d9..7a655d6208 100644 --- a/tests/auto/corelib.pro +++ b/tests/auto/corelib.pro @@ -30,6 +30,7 @@ SUBDIRS=\ qfileinfo \ qfilesystemwatcher \ qflags \ + qfreelist \ qfuture \ qfuturewatcher \ qgetputenv \ diff --git a/tests/auto/moc/moc.pro b/tests/auto/moc/moc.pro index 59106aa11d..056c6b0958 100644 --- a/tests/auto/moc/moc.pro +++ b/tests/auto/moc/moc.pro @@ -26,5 +26,3 @@ contains(QT_CONFIG, dbus){ QT += dbus } -CONFIG+=insignificant_test - diff --git a/tests/auto/qabstractnetworkcache/qabstractnetworkcache.pro b/tests/auto/qabstractnetworkcache/qabstractnetworkcache.pro index 6f5044f6bb..4dea3c9c8c 100644 --- a/tests/auto/qabstractnetworkcache/qabstractnetworkcache.pro +++ b/tests/auto/qabstractnetworkcache/qabstractnetworkcache.pro @@ -10,3 +10,5 @@ wince*|symbian: { } symbian: TARGET.CAPABILITY = NetworkServices + +CONFIG += insignificant_test # QTBUG-20686; note, assumed unstable on all platforms diff --git a/tests/auto/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/qcoreapplication/tst_qcoreapplication.cpp index 0b581af77b..99f0941ac2 100644 --- a/tests/auto/qcoreapplication/tst_qcoreapplication.cpp +++ b/tests/auto/qcoreapplication/tst_qcoreapplication.cpp @@ -361,26 +361,25 @@ class DeliverInDefinedOrderObject : public QObject QPointer thread; int count; + int startCount; + int loopLevel; public: DeliverInDefinedOrderObject(QObject *parent) - : QObject(parent), thread(0), count(0) + : QObject(parent), thread(0), count(0), startCount(0), loopLevel(0) { } - ~DeliverInDefinedOrderObject() - { - if (!thread.isNull()) - thread->wait(); - } + +signals: + void done(); public slots: - void start() + void startThread() { QVERIFY(!thread); thread = new DeliverInDefinedOrderThread(); connect(thread, SIGNAL(progress(int)), this, SLOT(threadProgress(int))); connect(thread, SIGNAL(finished()), this, SLOT(threadFinished())); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - connect(thread, SIGNAL(destroyed()), this, SLOT(start())); + connect(thread, SIGNAL(destroyed()), this, SLOT(threadDestroyed())); thread->start(); QCoreApplication::postEvent(this, new QEvent(QEvent::MaxUser), -1); @@ -398,21 +397,34 @@ public slots: { QVERIFY(count == 7); count = 0; + thread->deleteLater(); QCoreApplication::postEvent(this, new QEvent(QEvent::MaxUser), -1); } + void threadDestroyed() + { + if (++startCount < 20) + startThread(); + else + emit done(); + } + public: bool event(QEvent *event) { switch (event->type()) { case QEvent::User: - { - (void) QEventLoop().exec(); - break; + { + ++loopLevel; + if (loopLevel == 2) { + // Ready. Starts a thread that emits (queued) signals, which should be handled in order + startThread(); } - case QEvent::User + 1: + QCoreApplication::postEvent(this, new QEvent(QEvent::MaxUser), -1); + (void) QEventLoop().exec(); break; + } default: break; } @@ -430,11 +442,8 @@ void tst_QCoreApplication::deliverInDefinedOrder() // causes sendPostedEvents() to recurse twice QCoreApplication::postEvent(&obj, new QEvent(QEvent::User)); QCoreApplication::postEvent(&obj, new QEvent(QEvent::User)); - // starts a thread that emits (queued) signals, which should be handled in order - obj.start(); - // run for 15 seconds - QTimer::singleShot(15000, &app, SLOT(quit())); + QObject::connect(&obj, SIGNAL(done()), &app, SLOT(quit())); app.exec(); } #endif // QT_NO_QTHREAD @@ -524,7 +533,7 @@ void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents() QCoreApplication::processEvents(); QCOMPARE(object.counter, i); ++i; - } while (t.elapsed() < 3000); + } while (t.elapsed() < 1000); } void tst_QCoreApplication::reexec() diff --git a/tests/auto/qdialog/qdialog.pro b/tests/auto/qdialog/qdialog.pro index 0d59590117..7c4defacd9 100644 --- a/tests/auto/qdialog/qdialog.pro +++ b/tests/auto/qdialog/qdialog.pro @@ -1,6 +1,3 @@ load(qttest_p4) QT += widgets SOURCES += tst_qdialog.cpp - - -CONFIG+=insignificant_test diff --git a/tests/auto/qdialog/tst_qdialog.cpp b/tests/auto/qdialog/tst_qdialog.cpp index 6d9f7988cd..86dde21ba0 100644 --- a/tests/auto/qdialog/tst_qdialog.cpp +++ b/tests/auto/qdialog/tst_qdialog.cpp @@ -467,6 +467,22 @@ void tst_QDialog::throwInExec() #if defined(Q_WS_MAC) || (defined(Q_WS_WINCE) && defined(_ARM_)) QSKIP("Throwing exceptions in exec() is not supported on this platform.", SkipAll); #endif + +#if defined(Q_OS_LINUX) + // C++ exceptions can't be passed through glib callbacks. Skip the test if + // we're using the glib event loop. + QByteArray dispatcher = QAbstractEventDispatcher::instance()->metaObject()->className(); + if (dispatcher.contains("Glib")) { + QSKIP( + qPrintable(QString( + "Throwing exceptions in exec() won't work if %1 event dispatcher is used.\n" + "Try running with QT_NO_GLIB=1 in environment." + ).arg(QString::fromLatin1(dispatcher))), + SkipAll + ); + } +#endif + int caughtExceptions = 0; try { ExceptionDialog dialog; diff --git a/tests/auto/qdoublevalidator/tst_qdoublevalidator.cpp b/tests/auto/qdoublevalidator/tst_qdoublevalidator.cpp index 76d4494a39..6014ce5165 100644 --- a/tests/auto/qdoublevalidator/tst_qdoublevalidator.cpp +++ b/tests/auto/qdoublevalidator/tst_qdoublevalidator.cpp @@ -55,6 +55,7 @@ private slots: void validateThouSep(); void validateIntEquiv_data(); void validateIntEquiv(); + void notifySignals(); }; Q_DECLARE_METATYPE(QValidator::State); @@ -244,6 +245,62 @@ void tst_QDoubleValidator::validate() dv.setNotation(QDoubleValidator::StandardNotation); QCOMPARE((int)dv.validate(value, dummy), (int)standard_state); } +void tst_QDoubleValidator::notifySignals() +{ + QDoubleValidator dv(0.1, 0.9, 10, 0); + QSignalSpy topSpy(&dv, SIGNAL(topChanged(double))); + QSignalSpy bottomSpy(&dv, SIGNAL(bottomChanged(double))); + QSignalSpy decSpy(&dv, SIGNAL(decimalsChanged(int))); + + qRegisterMetaType("QDoubleValidator::Notation"); + QSignalSpy notSpy(&dv, SIGNAL(notationChanged(QDoubleValidator::Notation))); + + dv.setTop(0.8); + QCOMPARE(topSpy.count(), 1); + QVERIFY(dv.top() == 0.8); + dv.setBottom(0.2); + QCOMPARE(bottomSpy.count(), 1); + QVERIFY(dv.bottom() == 0.2); + + dv.setRange(0.2, 0.7); + QCOMPARE(topSpy.count(), 2); + QCOMPARE(bottomSpy.count(), 1); + QCOMPARE(decSpy.count(), 1); + QVERIFY(dv.bottom() == 0.2); + QVERIFY(dv.top() == 0.7); + QVERIFY(dv.decimals() == 0.); + + dv.setRange(0.3, 0.7); + QCOMPARE(topSpy.count(), 2); + QCOMPARE(bottomSpy.count(), 2); + QVERIFY(dv.bottom() == 0.3); + QVERIFY(dv.top() == 0.7); + QVERIFY(dv.decimals() == 0.); + + dv.setRange(0.4, 0.6); + QCOMPARE(topSpy.count(), 3); + QCOMPARE(bottomSpy.count(), 3); + QVERIFY(dv.bottom() == 0.4); + QVERIFY(dv.top() == 0.6); + QVERIFY(dv.decimals() == 0.); + + dv.setDecimals(10); + QCOMPARE(decSpy.count(), 2); + QVERIFY(dv.decimals() == 10.); + + + dv.setRange(0.4, 0.6, 100); + QCOMPARE(topSpy.count(), 3); + QCOMPARE(bottomSpy.count(), 3); + QCOMPARE(decSpy.count(), 3); + QVERIFY(dv.bottom() == 0.4); + QVERIFY(dv.top() == 0.6); + QVERIFY(dv.decimals() == 100.); + + dv.setNotation(QDoubleValidator::StandardNotation); + QCOMPARE(notSpy.count(), 1); + QVERIFY(dv.notation() == QDoubleValidator::StandardNotation); +} void tst_QDoubleValidator::validateIntEquiv_data() { diff --git a/tests/auto/qfile/test/test.pro b/tests/auto/qfile/test/test.pro index 0f211b9de5..f4ec12f874 100644 --- a/tests/auto/qfile/test/test.pro +++ b/tests/auto/qfile/test/test.pro @@ -41,4 +41,4 @@ symbian { LIBS+=-lefsrv } -CONFIG+=insignificant_test +mac*:CONFIG+=insignificant_test diff --git a/tests/auto/qfile/tst_qfile.cpp b/tests/auto/qfile/tst_qfile.cpp index 4a78876843..aafe79484e 100644 --- a/tests/auto/qfile/tst_qfile.cpp +++ b/tests/auto/qfile/tst_qfile.cpp @@ -2438,7 +2438,7 @@ void tst_QFile::rename_data() QTest::newRow("a -> b") << QString("a") << QString("b") << false; QTest::newRow("a -> .") << QString("a") << QString(".") << false; QTest::newRow("renamefile -> renamefile") << QString("renamefile") << QString("renamefile") << false; - QTest::newRow("renamefile -> Makefile") << QString("renamefile") << QString("Makefile") << false; + QTest::newRow("renamefile -> noreadfile") << QString("renamefile") << QString("noreadfile") << false; #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) QTest::newRow("renamefile -> /etc/renamefile") << QString("renamefile") << QString("/etc/renamefile") << false; #endif diff --git a/tests/auto/qfilesystemmodel/qfilesystemmodel.pro b/tests/auto/qfilesystemmodel/qfilesystemmodel.pro index 5c97761b99..b0b6d7a18d 100644 --- a/tests/auto/qfilesystemmodel/qfilesystemmodel.pro +++ b/tests/auto/qfilesystemmodel/qfilesystemmodel.pro @@ -15,5 +15,3 @@ symbian: { DEPLOYMENT += dummyDeploy LIBS += -lefsrv } - -CONFIG+=insignificant_test diff --git a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp index c2b3e7c521..a9a4fc7fc3 100644 --- a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -909,12 +909,16 @@ void tst_QFileSystemModel::sort() expectedOrder << tempFile2.fileName() << tempFile.fileName() << dirPath + QChar('/') + "." << dirPath + QChar('/') + ".."; //File dialog Mode means sub trees are not sorted, only the current root if (fileDialogMode) { + // FIXME: we were only able to disableRecursiveSort in developer builds, so we can only + // stably perform this test for developer builds +#ifdef QT_BUILD_INTERNAL QList actualRows; for(int i = 0; i < myModel->rowCount(parent); ++i) { actualRows << dirPath + QChar('/') + myModel->index(i, 1, parent).data(QFileSystemModel::FileNameRole).toString(); } QVERIFY(actualRows != expectedOrder); +#endif } else { for(int i = 0; i < myModel->rowCount(parent); ++i) { diff --git a/tests/auto/qfreelist/qfreelist.pro b/tests/auto/qfreelist/qfreelist.pro new file mode 100644 index 0000000000..b7f2b3d38f --- /dev/null +++ b/tests/auto/qfreelist/qfreelist.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qfreelist.cpp +QT += core-private +QT -= gui + +!private_tests:SOURCES += $$QT_SOURCE_TREE/src/corelib/tools/qfreelist.cpp diff --git a/tests/auto/qfreelist/tst_qfreelist.cpp b/tests/auto/qfreelist/tst_qfreelist.cpp new file mode 100644 index 0000000000..139d76e64a --- /dev/null +++ b/tests/auto/qfreelist/tst_qfreelist.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include +#include +#include + +//TESTED_CLASS=QFreeList +//TESTED_FILES=corelib/tools/qfreelist_p.h + +class tst_QFreeList : public QObject +{ + Q_OBJECT + +private slots: + void basicTest(); + void customized(); + void threadedTest(); +}; + +void tst_QFreeList::basicTest() +{ + { + QFreeList voidFreeList; + int zero = voidFreeList.next(); + int one = voidFreeList.next(); + int two = voidFreeList.next(); + QCOMPARE(zero, 0); + QCOMPARE(one, 1); + QCOMPARE(two, 2); + voidFreeList[zero]; + voidFreeList[one]; + voidFreeList[two]; + voidFreeList.at(zero); + voidFreeList.at(one); + voidFreeList.at(two); + voidFreeList.release(one); + int next = voidFreeList.next(); + QCOMPARE(next, 1); + voidFreeList[next]; + voidFreeList.at(next); + } + + { + QFreeList intFreeList; + int zero = intFreeList.next(); + int one = intFreeList.next(); + int two = intFreeList.next(); + QCOMPARE(zero, 0); + QCOMPARE(one, 1); + QCOMPARE(two, 2); + intFreeList[zero] = zero; + intFreeList[one] = one; + intFreeList[two] = two; + QCOMPARE(intFreeList.at(zero), zero); + QCOMPARE(intFreeList.at(one), one); + QCOMPARE(intFreeList.at(two), two); + intFreeList.release(one); + int next = intFreeList.next(); + QCOMPARE(next, 1); + QCOMPARE(intFreeList.at(next), one); + intFreeList[next] = -one; + QCOMPARE(intFreeList.at(next), -one); + } +} + +struct CustomFreeListConstants : public QFreeListDefaultConstants +{ + enum { + InitialNextValue = 50, + BlockCount = 10 + }; + + static const int Sizes[10]; +}; + +const int CustomFreeListConstants::Sizes[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 16777216 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 }; + +void tst_QFreeList::customized() +{ + QFreeList customFreeList; + int next = customFreeList.next(); + QCOMPARE(next, int(CustomFreeListConstants::InitialNextValue)); + customFreeList[next]; + customFreeList.at(next); + customFreeList.release(next); +} + +enum { TimeLimit = 3000 }; + +class FreeListThread : public QThread +{ + static QFreeList freelist; + +public: + inline FreeListThread() : QThread() { } + inline void run() + { + QElapsedTimer t; + t.start(); + QList needToRelease; + do { + int i = freelist.next(); + int j = freelist.next(); + int k = freelist.next(); + int l = freelist.next(); + freelist.release(k); + int n = freelist.next(); + int m = freelist.next(); + freelist.release(l); + freelist.release(m); + freelist.release(n); + freelist.release(j); + // freelist.release(i); + needToRelease << i; + } while (t.elapsed() < TimeLimit); + + foreach (int x, needToRelease) + freelist.release(x); + } +}; + +QFreeList FreeListThread::freelist; + +void tst_QFreeList::threadedTest() +{ + const int ThreadCount = QThread::idealThreadCount(); + FreeListThread *threads = new FreeListThread[ThreadCount]; + for (int i = 0; i < ThreadCount; ++i) + threads[i].start(); + for (int i = 0; i < ThreadCount; ++i) + threads[i].wait(); + delete [] threads; +} + +QTEST_MAIN(tst_QFreeList) +#include "tst_qfreelist.moc" diff --git a/tests/auto/qftp/qftp.pro b/tests/auto/qftp/qftp.pro index 42c700e72e..69f89572ba 100644 --- a/tests/auto/qftp/qftp.pro +++ b/tests/auto/qftp/qftp.pro @@ -18,5 +18,3 @@ wince*: { } else { DEFINES += SRCDIR=\\\"$$PWD/\\\" } - -CONFIG+=insignificant_test diff --git a/tests/auto/qftp/tst_qftp.cpp b/tests/auto/qftp/tst_qftp.cpp index 62b454099b..e31b5acda3 100644 --- a/tests/auto/qftp/tst_qftp.cpp +++ b/tests/auto/qftp/tst_qftp.cpp @@ -378,6 +378,8 @@ void tst_QFtp::connectToUnresponsiveHost() a lot of other stuff in QFtp, so we just expect this test to fail on Windows. */ QEXPECT_FAIL("", "timeout not working due to strange Windows socket behaviour (see source file of this test for explanation)", Abort); +#else + QEXPECT_FAIL("", "QTBUG-20687", Abort); #endif QVERIFY2(! QTestEventLoop::instance().timeout(), "Network timeout longer than expected (should have been 60 seconds)"); diff --git a/tests/auto/qglobal/tst_qglobal.cpp b/tests/auto/qglobal/tst_qglobal.cpp index 841151efc4..19a13f6ad0 100644 --- a/tests/auto/qglobal/tst_qglobal.cpp +++ b/tests/auto/qglobal/tst_qglobal.cpp @@ -130,10 +130,12 @@ void tst_QGlobal::qInternalCallbacks() QInternal::unregisterCallback(QInternal::DisconnectCallback, disconnect_callback); connect_info.reset(); + QTest::ignoreMessage(QtWarningMsg, "Object::connect: No such signal QObject::mysignal(x)"); ok = QObject::connect(&a, signal.toLatin1(), &b, slot.toLatin1(), Qt::AutoConnection); QVERIFY(!ok); QCOMPARE(connect_info.sender, (QObject *) 0); + QTest::ignoreMessage(QtWarningMsg, "Object::disconnect: No such signal QObject::mysignal(x)"); ok = QObject::disconnect(&a, signal.toLatin1(), &b, slot.toLatin1()); QVERIFY(!ok); QCOMPARE(connect_info.sender, (QObject *) 0); diff --git a/tests/auto/qgraphicstransform/qgraphicstransform.pro b/tests/auto/qgraphicstransform/qgraphicstransform.pro index 57cbb0e5bd..4f9d001717 100644 --- a/tests/auto/qgraphicstransform/qgraphicstransform.pro +++ b/tests/auto/qgraphicstransform/qgraphicstransform.pro @@ -2,5 +2,3 @@ load(qttest_p4) QT += widgets SOURCES += tst_qgraphicstransform.cpp CONFIG += parallel_test - -CONFIG+=insignificant_test diff --git a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp index f229ee7d5f..7b928909ff 100644 --- a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp +++ b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp @@ -61,6 +61,9 @@ private slots: void rotation3d(); void rotation3dArbitraryAxis_data(); void rotation3dArbitraryAxis(); + +private: + QString toString(QTransform const&); }; @@ -305,6 +308,15 @@ void tst_QGraphicsTransform::rotation3d() QVERIFY(transform2D(rotation).isIdentity()); } +QByteArray labelForTest(QVector3D const& axis, int angle) { + return QString("rotation of %1 on (%2, %3, %4)") + .arg(angle) + .arg(axis.x()) + .arg(axis.y()) + .arg(axis.z()) + .toLatin1(); +} + void tst_QGraphicsTransform::rotation3dArbitraryAxis_data() { QTest::addColumn("axis"); @@ -317,11 +329,11 @@ void tst_QGraphicsTransform::rotation3dArbitraryAxis_data() QVector3D axis5 = QVector3D(0.01f, 0.01f, 0.01f); for (int angle = 0; angle <= 360; angle++) { - QTest::newRow("test rotation on (1, 1, 1)") << axis1 << qreal(angle); - QTest::newRow("test rotation on (2, -3, .5)") << axis2 << qreal(angle); - QTest::newRow("test rotation on (-2, 0, -.5)") << axis3 << qreal(angle); - QTest::newRow("test rotation on (.0001, .0001, .0001)") << axis4 << qreal(angle); - QTest::newRow("test rotation on (.01, .01, .01)") << axis5 << qreal(angle); + QTest::newRow(labelForTest(axis1, angle).constData()) << axis1 << qreal(angle); + QTest::newRow(labelForTest(axis2, angle).constData()) << axis2 << qreal(angle); + QTest::newRow(labelForTest(axis3, angle).constData()) << axis3 << qreal(angle); + QTest::newRow(labelForTest(axis4, angle).constData()) << axis4 << qreal(angle); + QTest::newRow(labelForTest(axis5, angle).constData()) << axis5 << qreal(angle); } } @@ -347,7 +359,26 @@ void tst_QGraphicsTransform::rotation3dArbitraryAxis() exp.rotate(angle, axis); QTransform expected = exp.toTransform(1024.0f); - QVERIFY(fuzzyCompare(transform2D(rotation), expected)); +#ifdef Q_OS_LINUX + // These failures possibly relate to the float vs qreal issue mentioned + // in the comment above fuzzyCompare(). + if (sizeof(qreal) == sizeof(double)) { + QEXPECT_FAIL("rotation of 120 on (1, 1, 1)", "QTBUG-20661", Abort); + QEXPECT_FAIL("rotation of 240 on (1, 1, 1)", "QTBUG-20661", Abort); + QEXPECT_FAIL("rotation of 120 on (0.01, 0.01, 0.01)", "QTBUG-20661", Abort); + QEXPECT_FAIL("rotation of 240 on (0.01, 0.01, 0.01)", "QTBUG-20661", Abort); + QEXPECT_FAIL("rotation of 120 on (0.0001, 0.0001, 0.0001)", "QTBUG-20661", Abort); + QEXPECT_FAIL("rotation of 240 on (0.0001, 0.0001, 0.0001)", "QTBUG-20661", Abort); + } +#endif + + QTransform actual = transform2D(rotation); + QVERIFY2(fuzzyCompare(actual, expected), qPrintable( + QString("\nactual: %1\n" + "expected: %2") + .arg(toString(actual)) + .arg(toString(expected)) + )); // Check that "rotation" produces the 4x4 form of the 3x3 matrix. // i.e. third row and column are 0 0 1 0. @@ -357,6 +388,21 @@ void tst_QGraphicsTransform::rotation3dArbitraryAxis() QVERIFY(qFuzzyCompare(t, r)); } +QString tst_QGraphicsTransform::toString(QTransform const& t) +{ + return QString("[ [ %1 %2 %3 ]; [ %4 %5 %6 ]; [ %7 %8 %9 ] ]") + .arg(t.m11()) + .arg(t.m12()) + .arg(t.m13()) + .arg(t.m21()) + .arg(t.m22()) + .arg(t.m23()) + .arg(t.m31()) + .arg(t.m32()) + .arg(t.m33()) + ; +} + QTEST_MAIN(tst_QGraphicsTransform) #include "tst_qgraphicstransform.moc" diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index 196519096c..d6bc8ff3e8 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -104,6 +104,7 @@ static void sendMouseMove(QWidget *widget, const QPoint &point, Qt::MouseButton QTest::mouseMove(widget, point); QMouseEvent event(QEvent::MouseMove, point, button, buttons, 0); QApplication::sendEvent(widget, &event); + QApplication::processEvents(); } static void sendMouseRelease(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton) diff --git a/tests/auto/qicon/qicon.pro b/tests/auto/qicon/qicon.pro index aea7b9db64..cc87fae539 100644 --- a/tests/auto/qicon/qicon.pro +++ b/tests/auto/qicon/qicon.pro @@ -28,5 +28,3 @@ wince* { } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } - -CONFIG+=insignificant_test diff --git a/tests/auto/qicon/tst_qicon.cpp b/tests/auto/qicon/tst_qicon.cpp index cd3f84f4b0..4c430f9435 100644 --- a/tests/auto/qicon/tst_qicon.cpp +++ b/tests/auto/qicon/tst_qicon.cpp @@ -41,7 +41,7 @@ #include - +#include #include #if defined(Q_OS_SYMBIAN) @@ -87,6 +87,8 @@ private slots: void task239461_custom_iconengine_crash(); private: + bool haveImageFormat(QByteArray const&); + QString oldCurrentDir; const static QIcon staticIcon; @@ -112,6 +114,11 @@ void tst_QIcon::cleanup() } } +bool tst_QIcon::haveImageFormat(QByteArray const& desiredFormat) +{ + return QImageReader::supportedImageFormats().contains(desiredFormat); +} + tst_QIcon::tst_QIcon() { } @@ -205,6 +212,10 @@ void tst_QIcon::actualSize2() void tst_QIcon::svgActualSize() { + if (!haveImageFormat("svg")) { + QSKIP("SVG support is not available", SkipAll); + } + const QString prefix = QLatin1String(SRCDIR) + QLatin1String("/"); QIcon icon(prefix + "rect.svg"); QCOMPARE(icon.actualSize(QSize(16, 16)), QSize(16, 2)); @@ -415,6 +426,9 @@ void tst_QIcon::detach() void tst_QIcon::svg() { + if (!haveImageFormat("svg")) { + QSKIP("SVG support is not available", SkipAll); + } QIcon icon1("heart.svg"); QVERIFY(!icon1.pixmap(32).isNull()); @@ -521,14 +535,14 @@ void tst_QIcon::availableSizes() QCOMPARE(availableSizes.at(0), QSize(16,16)); } - { + if (haveImageFormat("svg")) { // checks that there are no availableSizes for scalable images. QIcon icon("heart.svg"); QList availableSizes = icon.availableSizes(); QVERIFY(availableSizes.isEmpty()); } - { + if (haveImageFormat("svg")) { // even if an a scalable image contain added pixmaps, // availableSizes still should be empty. QIcon icon("heart.svg"); diff --git a/tests/auto/qimagereader/images/test32bfv4.bmp b/tests/auto/qimagereader/images/test32bfv4.bmp new file mode 100644 index 0000000000..37060373ed Binary files /dev/null and b/tests/auto/qimagereader/images/test32bfv4.bmp differ diff --git a/tests/auto/qimagereader/images/test32v5.bmp b/tests/auto/qimagereader/images/test32v5.bmp new file mode 100644 index 0000000000..8ad3cfa60d Binary files /dev/null and b/tests/auto/qimagereader/images/test32v5.bmp differ diff --git a/tests/auto/qimagereader/qimagereader.pro b/tests/auto/qimagereader/qimagereader.pro index 34ec607570..43d587ea48 100644 --- a/tests/auto/qimagereader/qimagereader.pro +++ b/tests/auto/qimagereader/qimagereader.pro @@ -5,12 +5,6 @@ QT += widgets widgets-private core-private gui-private network RESOURCES += qimagereader.qrc !symbian:DEFINES += SRCDIR=\\\"$$PWD\\\" -!contains(QT_CONFIG, no-gif):DEFINES += QTEST_HAVE_GIF -!contains(QT_CONFIG, no-jpeg):DEFINES += QTEST_HAVE_JPEG -!contains(QT_CONFIG, no-mng):DEFINES += QTEST_HAVE_MNG -!contains(QT_CONFIG, no-tiff):DEFINES += QTEST_HAVE_TIFF -!contains(QT_CONFIG, no-svg):DEFINES += QTEST_HAVE_SVG - win32-msvc:QMAKE_CXXFLAGS -= -Zm200 win32-msvc:QMAKE_CXXFLAGS += -Zm800 win32-msvc.net:QMAKE_CXXFLAGS -= -Zm300 @@ -40,5 +34,3 @@ symbian: { DEPLOYMENT += imagePlugins } } - -CONFIG+=insignificant_test diff --git a/tests/auto/qimagereader/qimagereader.qrc b/tests/auto/qimagereader/qimagereader.qrc index 632b73abb0..2c70652389 100644 --- a/tests/auto/qimagereader/qimagereader.qrc +++ b/tests/auto/qimagereader/qimagereader.qrc @@ -42,6 +42,8 @@ images/teapot.ppm images/test.ppm images/test.xpm + images/test32bfv4.bmp + images/test32v5.bmp images/tst7.bmp images/tst7.png images/transparent.xpm diff --git a/tests/auto/qimagereader/tst_qimagereader.cpp b/tests/auto/qimagereader/tst_qimagereader.cpp index 5c65cb3044..6359468597 100644 --- a/tests/auto/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/qimagereader/tst_qimagereader.cpp @@ -143,12 +143,10 @@ private slots: void imageFormatBeforeRead_data(); void imageFormatBeforeRead(); -#if defined QTEST_HAVE_GIF void gifHandlerBugs(); void animatedGif(); void gifImageCount(); void gifLoopCount(); -#endif void readCorruptImage_data(); void readCorruptImage(); @@ -157,7 +155,6 @@ private slots: void supportsOption_data(); void supportsOption(); -#if defined QTEST_HAVE_TIFF void tiffCompression_data(); void tiffCompression(); void tiffEndianness(); @@ -166,7 +163,6 @@ private slots: void tiffOrientation(); void tiffGrayscale(); -#endif void autoDetectImageFormat(); void fileNameProbing(); @@ -192,6 +188,12 @@ private slots: static const QLatin1String prefix(SRCDIR "/images/"); +// helper to skip an autotest when the given image format is not supported +#define SKIP_IF_UNSUPPORTED(format) do { \ + if (!QByteArray(format).isEmpty() && !QImageReader::supportedImageFormats().contains(format)) \ + QSKIP("\"" + QByteArray(format) + "\" images are not supported", SkipSingle); \ +} while (0) + // Testing get/set functions void tst_QImageReader::getSetCheck() { @@ -234,6 +236,8 @@ void tst_QImageReader::readImage_data() QTest::newRow("empty") << QString() << false << QByteArray(); QTest::newRow("BMP: colorful") << QString("colorful.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << QString("test32bfv4.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << QString("test32v5.bmp") << true << QByteArray("bmp"); QTest::newRow("BMP: font") << QString("font.bmp") << true << QByteArray("bmp"); QTest::newRow("BMP: signed char") << QString("crash-signed-char.bmp") << true << QByteArray("bmp"); QTest::newRow("BMP: 4bpp RLE") << QString("4bpp-rle.bmp") << true << QByteArray("bmp"); @@ -247,22 +251,17 @@ void tst_QImageReader::readImage_data() QTest::newRow("PPM: test") << QString("test.ppm") << true << QByteArray("ppm"); QTest::newRow("XBM: gnus") << QString("gnus.xbm") << true << QByteArray("xbm"); -#if defined QTEST_HAVE_JPEG QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << true << QByteArray("jpeg"); QTest::newRow("JPEG: qtbug13653") << QString("qtbug13653-no_eoi.jpg") << true << QByteArray("jpeg"); -#endif -#if defined QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << QString("earth.gif") << true << QByteArray("gif"); QTest::newRow("GIF: trolltech") << QString("trolltech.gif") << true << QByteArray("gif"); -#endif -#if defined QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << QString("ball.mng") << true << QByteArray("mng"); QTest::newRow("MNG: fire") << QString("fire.mng") << true << QByteArray("mng"); -#endif -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << QString("rect.svg") << true << QByteArray("svg"); QTest::newRow("SVGZ: rect") << QString("rect.svgz") << true << QByteArray("svgz"); -#endif } void tst_QImageReader::readImage() @@ -271,6 +270,8 @@ void tst_QImageReader::readImage() QFETCH(bool, success); QFETCH(QByteArray, format); + SKIP_IF_UNSUPPORTED(format); + for (int i = 0; i < 2; ++i) { QImageReader io(prefix + fileName, i ? QByteArray() : format); if (success) { @@ -361,7 +362,7 @@ void tst_QImageReader::setScaledSize_data() QTest::newRow("PPM: runners") << "runners.ppm" << QSize(400, 400) << QByteArray("ppm"); QTest::newRow("PPM: test") << "test.ppm" << QSize(10, 10) << QByteArray("ppm"); QTest::newRow("XBM: gnus") << "gnus" << QSize(200, 200) << QByteArray("xbm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("JPEG: beavis A") << "beavis" << QSize(200, 200) << QByteArray("jpeg"); QTest::newRow("JPEG: beavis B") << "beavis" << QSize(175, 175) << QByteArray("jpeg"); QTest::newRow("JPEG: beavis C") << "beavis" << QSize(100, 100) << QByteArray("jpeg"); @@ -371,19 +372,15 @@ void tst_QImageReader::setScaledSize_data() QTest::newRow("JPEG: beavis G") << "beavis" << QSize(50, 45) << QByteArray("jpeg"); QTest::newRow("JPEG: beavis H") << "beavis" << QSize(43, 43) << QByteArray("jpeg"); QTest::newRow("JPEG: beavis I") << "beavis" << QSize(25, 25) << QByteArray("jpeg"); -#endif // QTEST_HAVE_JPEG -#ifdef QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << "earth" << QSize(200, 200) << QByteArray("gif"); QTest::newRow("GIF: trolltech") << "trolltech" << QSize(200, 200) << QByteArray("gif"); -#endif // QTEST_HAVE_GIF -#ifdef QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << "ball" << QSize(200, 200) << QByteArray("mng"); QTest::newRow("MNG: fire") << "fire" << QSize(200, 200) << QByteArray("mng"); -#endif // QTEST_HAVE_MNG -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << "rect" << QSize(200, 200) << QByteArray("svg"); QTest::newRow("SVGZ: rect") << "rect" << QSize(200, 200) << QByteArray("svgz"); -#endif } void tst_QImageReader::setScaledSize() @@ -392,8 +389,7 @@ void tst_QImageReader::setScaledSize() QFETCH(QSize, newSize); QFETCH(QByteArray, format); - if (!format.isEmpty() && !QImageReader::supportedImageFormats().contains(format)) - QSKIP("Qt does not support reading the \"" + format + "\" format", SkipSingle); + SKIP_IF_UNSUPPORTED(format); QImageReader reader(prefix + fileName); reader.setScaledSize(newSize); @@ -413,8 +409,7 @@ void tst_QImageReader::task255627_setNullScaledSize() QFETCH(QString, fileName); QFETCH(QByteArray, format); - if (!format.isEmpty() && !QImageReader::supportedImageFormats().contains(format)) - QSKIP("Qt does not support reading the \"" + format + "\" format", SkipSingle); + SKIP_IF_UNSUPPORTED(format); QImageReader reader(prefix + fileName); @@ -432,6 +427,8 @@ void tst_QImageReader::setClipRect_data() QTest::addColumn("newRect"); QTest::addColumn("format"); QTest::newRow("BMP: colorful") << "colorful" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << "test32bfv4" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << "test32v5" << QRect(0, 0, 50, 50) << QByteArray("bmp"); QTest::newRow("BMP: font") << "font" << QRect(0, 0, 50, 50) << QByteArray("bmp"); QTest::newRow("BMP: 4bpp uncompressed") << "tst7.bmp" << QRect(0, 0, 31, 31) << QByteArray("bmp"); QTest::newRow("XPM: marble") << "marble" << QRect(0, 0, 50, 50) << QByteArray("xpm"); @@ -440,21 +437,17 @@ void tst_QImageReader::setClipRect_data() QTest::newRow("PPM: runners") << "runners.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); QTest::newRow("PPM: test") << "test.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); QTest::newRow("XBM: gnus") << "gnus" << QRect(0, 0, 50, 50) << QByteArray("xbm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("JPEG: beavis") << "beavis" << QRect(0, 0, 50, 50) << QByteArray("jpeg"); -#endif // QTEST_HAVE_JPEG -#ifdef QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << "earth" << QRect(0, 0, 50, 50) << QByteArray("gif"); QTest::newRow("GIF: trolltech") << "trolltech" << QRect(0, 0, 50, 50) << QByteArray("gif"); -#endif // QTEST_HAVE_GIF -#ifdef QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << "ball" << QRect(0, 0, 50, 50) << QByteArray("mng"); QTest::newRow("MNG: fire") << "fire" << QRect(0, 0, 50, 50) << QByteArray("mng"); -#endif // QTEST_HAVE_MNG -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svg"); QTest::newRow("SVGZ: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svgz"); -#endif } void tst_QImageReader::setClipRect() @@ -463,8 +456,7 @@ void tst_QImageReader::setClipRect() QFETCH(QRect, newRect); QFETCH(QByteArray, format); - if (!format.isEmpty() && !QImageReader::supportedImageFormats().contains(format)) - QSKIP("Qt does not support reading the \"" + format + "\" format", SkipSingle); + SKIP_IF_UNSUPPORTED(format); QImageReader reader(prefix + fileName); reader.setClipRect(newRect); @@ -484,6 +476,8 @@ void tst_QImageReader::setScaledClipRect_data() QTest::addColumn("format"); QTest::newRow("BMP: colorful") << "colorful" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << "test32bfv4" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << "test32v5" << QRect(0, 0, 50, 50) << QByteArray("bmp"); QTest::newRow("BMP: font") << "font" << QRect(0, 0, 50, 50) << QByteArray("bmp"); QTest::newRow("XPM: marble") << "marble" << QRect(0, 0, 50, 50) << QByteArray("xpm"); QTest::newRow("PNG: kollada") << "kollada" << QRect(0, 0, 50, 50) << QByteArray("png"); @@ -491,21 +485,17 @@ void tst_QImageReader::setScaledClipRect_data() QTest::newRow("PPM: runners") << "runners.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); QTest::newRow("PPM: test") << "test.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); QTest::newRow("XBM: gnus") << "gnus" << QRect(0, 0, 50, 50) << QByteArray("xbm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("JPEG: beavis") << "beavis" << QRect(0, 0, 50, 50) << QByteArray("jpeg"); -#endif // QTEST_HAVE_JPEG -#ifdef QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << "earth" << QRect(0, 0, 50, 50) << QByteArray("gif"); QTest::newRow("GIF: trolltech") << "trolltech" << QRect(0, 0, 50, 50) << QByteArray("gif"); -#endif // QTEST_HAVE_GIF -#ifdef QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << "ball" << QRect(0, 0, 50, 50) << QByteArray("mng"); QTest::newRow("MNG: fire") << "fire" << QRect(0, 0, 50, 50) << QByteArray("mng"); -#endif // QTEST_HAVE_MNG -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svg"); QTest::newRow("SVGZ: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svgz"); -#endif } void tst_QImageReader::setScaledClipRect() @@ -514,8 +504,7 @@ void tst_QImageReader::setScaledClipRect() QFETCH(QRect, newRect); QFETCH(QByteArray, format); - if (!format.isEmpty() && !QImageReader::supportedImageFormats().contains(format)) - QSKIP("Qt does not support reading the \"" + format + "\" format", SkipSingle); + SKIP_IF_UNSUPPORTED(format); QImageReader reader(prefix + fileName); reader.setScaledSize(QSize(300, 300)); @@ -542,19 +531,20 @@ void tst_QImageReader::imageFormat_data() QTest::newRow("ppm-2") << QString("teapot.ppm") << QByteArray("ppm") << QImage::Format_RGB32; QTest::newRow("ppm-3") << QString("runners.ppm") << QByteArray("ppm") << QImage::Format_RGB32; QTest::newRow("ppm-4") << QString("test.ppm") << QByteArray("ppm") << QImage::Format_RGB32; -#ifdef QTEST_HAVE_JPEG + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg") << QImage::Format_Indexed8; QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg") << QImage::Format_RGB32; QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg") << QImage::Format_RGB32; -#endif -#if defined QTEST_HAVE_GIF + QTest::newRow("gif-1") << QString("earth.gif") << QByteArray("gif") << QImage::Format_Invalid; QTest::newRow("gif-2") << QString("trolltech.gif") << QByteArray("gif") << QImage::Format_Invalid; -#endif + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm") << QImage::Format_MonoLSB; QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm") << QImage::Format_Indexed8; QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp") << QImage::Format_Indexed8; QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp") << QImage::Format_Indexed8; + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp") << QImage::Format_RGB32; + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp") << QImage::Format_RGB32; QTest::newRow("png") << QString("kollada.png") << QByteArray("png") << QImage::Format_ARGB32; QTest::newRow("png-2") << QString("YCbCr_cmyk.png") << QByteArray("png") << QImage::Format_RGB32; QTest::newRow("mng-1") << QString("ball.mng") << QByteArray("mng") << QImage::Format_Invalid; @@ -569,27 +559,9 @@ void tst_QImageReader::imageFormat() QFETCH(QByteArray, format); QFETCH(QImage::Format, imageFormat); - if (QImageReader::imageFormat(prefix + fileName).isEmpty()) { - if (QByteArray("jpeg") == format) -#ifndef QTEST_HAVE_JPEG - return; -#endif // !QTEST_HAVE_JPEG - if (QByteArray("gif") == format) -#ifndef QTEST_HAVE_GIF - return; -#endif // !QTEST_HAVE_GIF - if (QByteArray("mng") == format) -#ifndef QTEST_HAVE_MNG - return; -#endif // !QTEST_HAVE_MNG - if (QByteArray("svg") == format || QByteArray("svgz") == format) -#ifndef QTEST_HAVE_SVG - return; -#endif // !QTEST_HAVE_SVG - QSKIP(("Qt does not support the " + format + " format.").constData(), SkipSingle); - } else { - QCOMPARE(QImageReader::imageFormat(prefix + fileName), format); - } + SKIP_IF_UNSUPPORTED(format); + + QCOMPARE(QImageReader::imageFormat(prefix + fileName), format); QImageReader reader(prefix + fileName); QCOMPARE(reader.imageFormat(), imageFormat); } @@ -649,21 +621,17 @@ void tst_QImageReader::setBackgroundColor_data() QTest::newRow("PPM: runners") << QString("runners.ppm") << QColor(Qt::red); QTest::newRow("PPM: test") << QString("test.ppm") << QColor(Qt::white); QTest::newRow("XBM: gnus") << QString("gnus.xbm") << QColor(Qt::blue); -#if defined QTEST_HAVE_JPEG + QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << QColor(Qt::darkBlue); -#endif -#if defined QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << QString("earth.gif") << QColor(Qt::cyan); QTest::newRow("GIF: trolltech") << QString("trolltech.gif") << QColor(Qt::magenta); -#endif -#if defined QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << QString("ball.mng") << QColor(Qt::yellow); QTest::newRow("MNG: fire") << QString("fire.mng") << QColor(Qt::gray); -#endif -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << QString("rect.svg") << QColor(Qt::darkGreen); QTest::newRow("SVGZ: rect") << QString("rect.svgz") << QColor(Qt::darkGreen); -#endif } void tst_QImageReader::setBackgroundColor() @@ -684,27 +652,25 @@ void tst_QImageReader::supportsAnimation_data() QTest::newRow("BMP: colorful") << QString("colorful.bmp") << false; QTest::newRow("BMP: font") << QString("font.bmp") << false; QTest::newRow("BMP: signed char") << QString("crash-signed-char.bmp") << false; + QTest::newRow("BMP: test32bfv4") << QString("test32bfv4.bmp") << false;; + QTest::newRow("BMP: test32v5") << QString("test32v5.bmp") << false; QTest::newRow("XPM: marble") << QString("marble.xpm") << false; QTest::newRow("PNG: kollada") << QString("kollada.png") << false; QTest::newRow("PPM: teapot") << QString("teapot.ppm") << false; QTest::newRow("PPM: teapot") << QString("teapot.ppm") << false; QTest::newRow("PPM: runners") << QString("runners.ppm") << false; QTest::newRow("XBM: gnus") << QString("gnus.xbm") << false; -#if defined QTEST_HAVE_JPEG + QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << false; -#endif -#if defined QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << QString("earth.gif") << true; QTest::newRow("GIF: trolltech") << QString("trolltech.gif") << true; -#endif -#if defined QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << QString("ball.mng") << true; QTest::newRow("MNG: fire") << QString("fire.mng") << true; -#endif -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << QString("rect.svg") << false; QTest::newRow("SVGZ: rect") << QString("rect.svgz") << false; -#endif } void tst_QImageReader::supportsAnimation() @@ -724,6 +690,9 @@ void tst_QImageReader::sizeBeforeRead() { QFETCH(QString, fileName); QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + QImageReader reader(prefix + fileName); QVERIFY(reader.canRead()); if (format == "mng") { @@ -771,7 +740,11 @@ void tst_QImageReader::imageFormatBeforeRead_data() void tst_QImageReader::imageFormatBeforeRead() { QFETCH(QString, fileName); + QFETCH(QByteArray, format); QFETCH(QImage::Format, imageFormat); + + SKIP_IF_UNSUPPORTED(format); + QImageReader reader(fileName); if (reader.supportsOption(QImageIOHandler::ImageFormat)) { QImage::Format fileFormat = reader.imageFormat(); @@ -783,9 +756,10 @@ void tst_QImageReader::imageFormatBeforeRead() } } -#if defined QTEST_HAVE_GIF void tst_QImageReader::gifHandlerBugs() { + SKIP_IF_UNSUPPORTED("gif"); + { QImageReader io(prefix + "trolltech.gif"); QVERIFY(io.loopCount() != 1); @@ -827,6 +801,8 @@ void tst_QImageReader::gifHandlerBugs() void tst_QImageReader::animatedGif() { + SKIP_IF_UNSUPPORTED("gif"); + QImageReader io(":images/qt.gif"); QImage image = io.read(); QVERIFY(!image.isNull()); @@ -842,6 +818,8 @@ void tst_QImageReader::animatedGif() // Check the count of images in various call orders... void tst_QImageReader::gifImageCount() { + SKIP_IF_UNSUPPORTED("gif"); + // just read every frame... and see how much we got.. { QImageReader io(":images/four-frames.gif"); @@ -977,6 +955,8 @@ void tst_QImageReader::gifImageCount() void tst_QImageReader::gifLoopCount() { + SKIP_IF_UNSUPPORTED("gif"); + { QImageReader io(":images/qt-gif-anim.gif"); QCOMPARE(io.loopCount(), -1); // infinite loop @@ -987,8 +967,6 @@ void tst_QImageReader::gifLoopCount() } } -#endif - class Server : public QObject { Q_OBJECT @@ -1050,29 +1028,28 @@ void tst_QImageReader::readFromDevice_data() QTest::newRow("ppm-2") << QString("teapot.ppm") << QByteArray("ppm"); QTest::newRow("ppm-3") << QString("teapot.ppm") << QByteArray("ppm"); QTest::newRow("ppm-4") << QString("runners.ppm") << QByteArray("ppm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-4") << QString("qtbug13653-no_eoi.jpg") << QByteArray("jpeg"); -#endif // QTEST_HAVE_JPEG -#ifdef QTEST_HAVE_GIF + QTest::newRow("gif-1") << QString("earth.gif") << QByteArray("gif"); QTest::newRow("gif-2") << QString("trolltech.gif") << QByteArray("gif"); -#endif // QTEST_HAVE_GIF + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm"); QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); -#ifdef QTEST_HAVE_MNG + QTest::newRow("mng-1") << QString("ball.mng") << QByteArray("mng"); QTest::newRow("mng-2") << QString("fire.mng") << QByteArray("mng"); -#endif // QTEST_HAVE_MNG -#if defined QTEST_HAVE_SVG + QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg"); QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz"); -#endif } void tst_QImageReader::readFromDevice() @@ -1080,6 +1057,8 @@ void tst_QImageReader::readFromDevice() QFETCH(QString, fileName); QFETCH(QByteArray, format); + SKIP_IF_UNSUPPORTED(format); + QImage expectedImage(prefix + fileName, format); QFile file(prefix + fileName); @@ -1142,26 +1121,20 @@ void tst_QImageReader::readFromFileAfterJunk_data() QTest::newRow("ppm-2") << QString("teapot.ppm") << QByteArray("ppm"); QTest::newRow("ppm-3") << QString("teapot.ppm") << QByteArray("ppm"); QTest::newRow("ppm-4") << QString("runners.ppm") << QByteArray("ppm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg"); -#endif -#if defined QTEST_HAVE_GIF -// QTest::newRow("gif-1") << QString("images/earth.gif") << QByteArray("gif"); -// QTest::newRow("gif-2") << QString("images/trolltech.gif") << QByteArray("gif"); -#endif + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm"); QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); -// QTest::newRow("mng-1") << QString("images/ball.mng") << QByteArray("mng"); -// QTest::newRow("mng-2") << QString("images/fire.mng") << QByteArray("mng"); -#if defined QTEST_HAVE_SVG QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg"); QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz"); -#endif } void tst_QImageReader::readFromFileAfterJunk() @@ -1169,10 +1142,7 @@ void tst_QImageReader::readFromFileAfterJunk() QFETCH(QString, fileName); QFETCH(QByteArray, format); - if (!QImageReader::supportedImageFormats().contains(format)) { - QString cause = QString("Skipping %1; no %2 support").arg(fileName).arg(QString(format)); - QSKIP(qPrintable(cause), SkipSingle); - } + SKIP_IF_UNSUPPORTED(format); QFile::remove("junk"); QFile junkFile("junk"); @@ -1221,25 +1191,22 @@ void tst_QImageReader::devicePosition_data() QTest::newRow("pbm") << QString("image.pbm") << QByteArray("pbm"); QTest::newRow("pgm") << QString("image.pgm") << QByteArray("pgm"); QTest::newRow("ppm-1") << QString("image.ppm") << QByteArray("ppm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg"); -#endif -#if defined QTEST_HAVE_GIF + QTest::newRow("gif-1") << QString("earth.gif") << QByteArray("gif"); -#endif + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm"); QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); -// QTest::newRow("mng-1") << QString("images/ball.mng") << QByteArray("mng"); -// QTest::newRow("mng-2") << QString("images/fire.mng") << QByteArray("mng"); -#if defined QTEST_HAVE_SVG QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg"); QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz"); -#endif } void tst_QImageReader::devicePosition() @@ -1247,6 +1214,8 @@ void tst_QImageReader::devicePosition() QFETCH(QString, fileName); QFETCH(QByteArray, format); + SKIP_IF_UNSUPPORTED(format); + QImage expected(prefix + fileName); QVERIFY(!expected.isNull()); @@ -1305,7 +1274,12 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("4bpp-rle.bmp") << QString("4bpp-rle.bmp") << QByteArray("bmp") << QSize(640, 480) << QString(""); -#ifdef QTEST_HAVE_GIF + QTest::newRow("test32bfv4.bmp") << QString("test32bfv4.bmp") + << QByteArray("bmp") << QSize(373, 156) + << QString(""); + QTest::newRow("test32v5.bmp") << QString("test32v5.bmp") + << QByteArray("bmp") << QSize(373, 156) + << QString(""); QTest::newRow("corrupt.gif") << QString("corrupt.gif") << QByteArray("gif") << QSize(0, 0) << QString(""); @@ -1324,8 +1298,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("bat2.gif") << QString("bat2.gif") << QByteArray("gif") << QSize(32, 32) << QString(""); -#endif -#ifdef QTEST_HAVE_JPEG QTest::newRow("corrupt.jpg") << QString("corrupt.jpg") << QByteArray("jpg") << QSize(0, 0) << QString("JPEG datastream contains no image"); @@ -1341,8 +1313,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("qtbug13653-no_eoi.jpg") << QString("qtbug13653-no_eoi.jpg") << QByteArray("jpg") << QSize(240, 180) << QString(""); -#endif -#ifdef QTEST_HAVE_MNG QTest::newRow("corrupt.mng") << QString("corrupt.mng") << QByteArray("mng") << QSize(0, 0) << QString("MNG error 901: Application signalled I/O error; chunk IHDR; subcode 0:0"); @@ -1352,8 +1322,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("ball.mng") << QString("ball.mng") << QByteArray("mng") << QSize(32, 32) << QString(""); -#endif -#ifdef QTEST_HAVE_SVG QTest::newRow("rect.svg") << QString("rect.svg") << QByteArray("svg") << QSize(105, 137) << QString(""); @@ -1366,7 +1334,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("corrupt.svgz") << QString("corrupt.svgz") << QByteArray("svgz") << QSize(0, 0) << QString(""); -#endif QTest::newRow("image.pbm") << QString("image.pbm") << QByteArray("pbm") << QSize(16, 6) << QString(""); @@ -1403,7 +1370,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("test.ppm") << QString("test.ppm") << QByteArray("ppm") << QSize(10, 10) << QString(""); -// QTest::newRow("corrupt.xbm") << QString("corrupt.xbm") << QByteArray("xbm") << QSize(0, 0); QTest::newRow("gnus.xbm") << QString("gnus.xbm") << QByteArray("xbm") << QSize(271, 273) << QString(""); @@ -1442,6 +1408,9 @@ void tst_QImageReader::readFromResources() QFETCH(QByteArray, format); QFETCH(QSize, size); QFETCH(QString, message); + + SKIP_IF_UNSUPPORTED(format); + for (int i = 0; i < 2; ++i) { QString file = i ? (":/images/" + fileName) : (prefix + fileName); { @@ -1515,31 +1484,26 @@ void tst_QImageReader::readCorruptImage_data() QTest::addColumn("fileName"); QTest::addColumn("shouldFail"); QTest::addColumn("message"); -#if defined QTEST_HAVE_JPEG + QTest::addColumn("format"); QTest::newRow("corrupt jpeg") << QString("corrupt.jpg") << true - << QString("JPEG datastream contains no image"); -#endif -#if defined QTEST_HAVE_GIF - QTest::newRow("corrupt gif") << QString("corrupt.gif") << true << QString(""); -#endif -#ifdef QTEST_HAVE_MNG + << QString("JPEG datastream contains no image") + << QByteArray("jpeg"); + QTest::newRow("corrupt gif") << QString("corrupt.gif") << true << QString("") << QByteArray("gif"); QTest::newRow("corrupt mng") << QString("corrupt.mng") << true - << QString("MNG error 901: Application signalled I/O error; chunk IHDR; subcode 0:0"); -#endif - QTest::newRow("corrupt png") << QString("corrupt.png") << true << QString(""); - QTest::newRow("corrupt bmp") << QString("corrupt.bmp") << true << QString(""); + << QString("MNG error 901: Application signalled I/O error; chunk IHDR; subcode 0:0") + << QByteArray("mng"); + QTest::newRow("corrupt png") << QString("corrupt.png") << true << QString("") << QByteArray("png"); + QTest::newRow("corrupt bmp") << QString("corrupt.bmp") << true << QString("") << QByteArray("bmp"); QTest::newRow("corrupt xpm (colors)") << QString("corrupt-colors.xpm") << true - << QString("QImage: XPM color specification is missing: bla9an.n#x"); + << QString("QImage: XPM color specification is missing: bla9an.n#x") + << QByteArray("xpm"); QTest::newRow("corrupt xpm (pixels)") << QString("corrupt-pixels.xpm") << true - << QString("QImage: XPM pixels missing on image line 3"); - QTest::newRow("corrupt xbm") << QString("corrupt.xbm") << false << QString(""); -#if defined QTEST_HAVE_TIFF - QTest::newRow("corrupt tiff") << QString("corrupt-data.tif") << true << QString(""); -#endif -#if defined QTEST_HAVE_SVG - QTest::newRow("corrupt svg") << QString("corrupt.svg") << true << QString(""); - QTest::newRow("corrupt svgz") << QString("corrupt.svgz") << true << QString(""); -#endif + << QString("QImage: XPM pixels missing on image line 3") + << QByteArray("xpm"); + QTest::newRow("corrupt xbm") << QString("corrupt.xbm") << false << QString("") << QByteArray("xbm"); + QTest::newRow("corrupt tiff") << QString("corrupt-data.tif") << true << QString("") << QByteArray("tiff"); + QTest::newRow("corrupt svg") << QString("corrupt.svg") << true << QString("") << QByteArray("svg"); + QTest::newRow("corrupt svgz") << QString("corrupt.svgz") << true << QString("") << QByteArray("svgz"); } void tst_QImageReader::readCorruptImage() @@ -1547,6 +1511,9 @@ void tst_QImageReader::readCorruptImage() QFETCH(QString, fileName); QFETCH(bool, shouldFail); QFETCH(QString, message); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); if (!message.isEmpty()) QTest::ignoreMessage(QtWarningMsg, message.toLatin1()); @@ -1603,7 +1570,6 @@ void tst_QImageReader::supportsOption() QVERIFY(!reader.supportsOption(option)); } -#if defined QTEST_HAVE_TIFF void tst_QImageReader::tiffCompression_data() { QTest::addColumn("uncompressedFile"); @@ -1624,6 +1590,8 @@ void tst_QImageReader::tiffCompression() QFETCH(QString, uncompressedFile); QFETCH(QString, compressedFile); + SKIP_IF_UNSUPPORTED("tiff"); + QImage uncompressedImage(prefix + uncompressedFile); QImage compressedImage(prefix + compressedFile); @@ -1632,6 +1600,8 @@ void tst_QImageReader::tiffCompression() void tst_QImageReader::tiffEndianness() { + SKIP_IF_UNSUPPORTED("tiff"); + QImage littleEndian(prefix + "rgba_nocompression_littleendian.tif"); QImage bigEndian(prefix + "rgba_nocompression_bigendian.tif"); @@ -1675,6 +1645,8 @@ void tst_QImageReader::tiffOrientation() QFETCH(QString, expected); QFETCH(QString, oriented); + SKIP_IF_UNSUPPORTED("tiff"); + QImage expectedImage(prefix + expected); QImage orientedImage(prefix + oriented); QCOMPARE(expectedImage, orientedImage); @@ -1682,22 +1654,22 @@ void tst_QImageReader::tiffOrientation() void tst_QImageReader::tiffGrayscale() { + SKIP_IF_UNSUPPORTED("tiff"); + QImage actualImage(prefix + "grayscale.tif"); QImage expectedImage(prefix + "grayscale-ref.tif"); QCOMPARE(expectedImage, actualImage.convertToFormat(expectedImage.format())); } -#endif void tst_QImageReader::dotsPerMeter_data() { QTest::addColumn("fileName"); QTest::addColumn("expectedDotsPerMeterX"); QTest::addColumn("expectedDotsPerMeterY"); -#if defined QTEST_HAVE_TIFF - QTest::newRow("TIFF: 72 dpi") << ("rgba_nocompression_littleendian.tif") << qRound(72 * (100 / 2.54)) << qRound(72 * (100 / 2.54)); - QTest::newRow("TIFF: 100 dpi") << ("image_100dpi.tif") << qRound(100 * (100 / 2.54)) << qRound(100 * (100 / 2.54)); -#endif + QTest::addColumn("format"); + QTest::newRow("TIFF: 72 dpi") << ("rgba_nocompression_littleendian.tif") << qRound(72 * (100 / 2.54)) << qRound(72 * (100 / 2.54)) << QByteArray("tiff"); + QTest::newRow("TIFF: 100 dpi") << ("image_100dpi.tif") << qRound(100 * (100 / 2.54)) << qRound(100 * (100 / 2.54)) << QByteArray("tiff"); } void tst_QImageReader::dotsPerMeter() @@ -1705,6 +1677,9 @@ void tst_QImageReader::dotsPerMeter() QFETCH(QString, fileName); QFETCH(int, expectedDotsPerMeterX); QFETCH(int, expectedDotsPerMeterY); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); QImage image(prefix + fileName); @@ -1717,10 +1692,9 @@ void tst_QImageReader::physicalDpi_data() QTest::addColumn("fileName"); QTest::addColumn("expectedPhysicalDpiX"); QTest::addColumn("expectedPhysicalDpiY"); -#if defined QTEST_HAVE_TIFF - QTest::newRow("TIFF: 72 dpi") << "rgba_nocompression_littleendian.tif" << 72 << 72; - QTest::newRow("TIFF: 100 dpi") << "image_100dpi.tif" << 100 << 100; -#endif + QTest::addColumn("format"); + QTest::newRow("TIFF: 72 dpi") << "rgba_nocompression_littleendian.tif" << 72 << 72 << QByteArray("tiff"); + QTest::newRow("TIFF: 100 dpi") << "image_100dpi.tif" << 100 << 100 << QByteArray("tiff"); } void tst_QImageReader::physicalDpi() @@ -1728,6 +1702,9 @@ void tst_QImageReader::physicalDpi() QFETCH(QString, fileName); QFETCH(int, expectedPhysicalDpiX); QFETCH(int, expectedPhysicalDpiY); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); QImage image(prefix + fileName); @@ -1769,21 +1746,19 @@ void tst_QImageReader::autoDetectImageFormat() QVERIFY(!reader.read().isNull()); } -#ifdef QTEST_HAVE_JPEG - { + if (QImageReader::supportedImageFormats().contains("jpeg")) { QImageReader io(prefix + "YCbCr_rgb.jpg"); io.setAutoDetectImageFormat(false); // This should fail since no format string is given QImage image; QVERIFY(!io.read(&image)); } - { + if (QImageReader::supportedImageFormats().contains("jpeg")) { QImageReader io(prefix + "YCbCr_rgb.jpg", "jpg"); io.setAutoDetectImageFormat(false); QImage image; QVERIFY(io.read(&image)); } -#endif { QImageReader io(prefix + "tst7.png"); io.setAutoDetectImageFormat(false); @@ -1873,26 +1848,16 @@ void tst_QImageReader::testIgnoresFormatAndExtension_data() QTest::newRow("image.pbm") << "image" << "pbm" << "pbm"; QTest::newRow("image.pgm") << "image" << "pgm" << "pgm"; -#if defined QTEST_HAVE_GIF QTest::newRow("bat1.gif") << "bat1" << "gif" << "gif"; -#endif -#if defined QTEST_HAVE_JPEG QTest::newRow("beavis.jpg") << "beavis" << "jpg" << "jpeg"; -#endif -#if defined QTEST_HAVE_MNG QTest::newRow("fire.mng") << "fire" << "mng" << "mng"; -#endif -#if defined QTEST_HAVE_TIFF QTest::newRow("image_100dpi.tif") << "image_100dpi" << "tif" << "tiff"; -#endif -#if defined QTEST_HAVE_SVG QTest::newRow("rect.svg") << "rect" << "svg" << "svg"; QTest::newRow("rect.svgz") << "rect" << "svgz" << "svgz"; -#endif } @@ -1902,6 +1867,8 @@ void tst_QImageReader::testIgnoresFormatAndExtension() QFETCH(QString, extension); QFETCH(QString, expected); + SKIP_IF_UNSUPPORTED(expected.toLatin1()); + QList formats = QImageReader::supportedImageFormats(); QString fileNameBase = prefix + name + "."; diff --git a/tests/auto/qintvalidator/tst_qintvalidator.cpp b/tests/auto/qintvalidator/tst_qintvalidator.cpp index d53763566d..369e3254e8 100644 --- a/tests/auto/qintvalidator/tst_qintvalidator.cpp +++ b/tests/auto/qintvalidator/tst_qintvalidator.cpp @@ -51,6 +51,7 @@ private slots: void validate(); void validateArabic(); void validateFrench(); + void notifySignals(); }; Q_DECLARE_METATYPE(QValidator::State); @@ -189,7 +190,6 @@ void tst_QIntValidator::validateFrench() QIntValidator validator(-2000, 2000, 0); validator.setLocale(QLocale::French); int i; - QString s = QLatin1String("1 "); QCOMPARE(validator.validate(s, i), QValidator::Acceptable); validator.fixup(s); @@ -220,5 +220,36 @@ void tst_QIntValidator::validate() QCOMPARE((int)iv.validate(value, dummy), (int)state); } +void tst_QIntValidator::notifySignals() +{ + QIntValidator iv(0, 10, 0); + QSignalSpy topSpy(&iv, SIGNAL(topChanged(int))); + QSignalSpy bottomSpy(&iv, SIGNAL(bottomChanged(int))); + iv.setTop(9); + QCOMPARE(topSpy.count(), 1); + QVERIFY(iv.top() == 9); + iv.setBottom(1); + QCOMPARE(bottomSpy.count(), 1); + QVERIFY(iv.bottom() == 1); + + iv.setRange(1, 8); + QCOMPARE(topSpy.count(), 2); + QCOMPARE(bottomSpy.count(), 1); + QVERIFY(iv.top() == 8); + QVERIFY(iv.bottom() == 1); + + iv.setRange(2, 8); + QCOMPARE(topSpy.count(), 2); + QCOMPARE(bottomSpy.count(), 2); + QVERIFY(iv.top() == 8); + QVERIFY(iv.bottom() == 2); + + iv.setRange(3, 7); + QCOMPARE(topSpy.count(), 3); + QCOMPARE(bottomSpy.count(), 3); + QVERIFY(iv.top() == 7); + QVERIFY(iv.bottom() == 3); +} + QTEST_MAIN(tst_QIntValidator) #include "tst_qintvalidator.moc" diff --git a/tests/auto/qiodevice/tst_qiodevice.cpp b/tests/auto/qiodevice/tst_qiodevice.cpp index 70debfa1f3..a0f57f9d8d 100644 --- a/tests/auto/qiodevice/tst_qiodevice.cpp +++ b/tests/auto/qiodevice/tst_qiodevice.cpp @@ -129,11 +129,11 @@ void tst_QIODevice::constructing_QTcpSocket() QVERIFY(!device->isOpen()); socket.connectToHost(QtNetworkSettings::serverName(), 143); - QVERIFY(socket.waitForConnected(5000)); + QVERIFY(socket.waitForConnected(30000)); QVERIFY(device->isOpen()); while (!device->canReadLine()) - QVERIFY(device->waitForReadyRead(5000)); + QVERIFY(device->waitForReadyRead(30000)); char buf[1024]; memset(buf, 0, sizeof(buf)); @@ -143,11 +143,11 @@ void tst_QIODevice::constructing_QTcpSocket() socket.close(); socket.connectToHost(QtNetworkSettings::serverName(), 143); - QVERIFY(socket.waitForConnected(5000)); + QVERIFY(socket.waitForConnected(30000)); QVERIFY(device->isOpen()); while (!device->canReadLine()) - QVERIFY(device->waitForReadyRead(5000)); + QVERIFY(device->waitForReadyRead(30000)); char buf2[1024]; memset(buf2, 0, sizeof(buf2)); diff --git a/tests/auto/qlibrary/tst_qlibrary.cpp b/tests/auto/qlibrary/tst_qlibrary.cpp index 0c31fddfdb..675d0e6ab6 100644 --- a/tests/auto/qlibrary/tst_qlibrary.cpp +++ b/tests/auto/qlibrary/tst_qlibrary.cpp @@ -297,7 +297,7 @@ void tst_QLibrary::unload_after_implicit_load() #endif QLibrary library( "./mylib" ); - void *p = library.resolve("mylibversion"); + QFunctionPointer p = library.resolve("mylibversion"); QVERIFY(p); // Check if it was loaded QVERIFY(library.isLoaded()); QVERIFY(library.unload()); diff --git a/tests/auto/qlineedit/tst_qlineedit.cpp b/tests/auto/qlineedit/tst_qlineedit.cpp index 92574ea01b..68e88a87ed 100644 --- a/tests/auto/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/qlineedit/tst_qlineedit.cpp @@ -72,6 +72,8 @@ #include "qcommonstyle.h" #include "qstyleoption.h" +#include "qplatformdefs.h" + QT_BEGIN_NAMESPACE class QPainter; QT_END_NAMESPACE @@ -180,6 +182,10 @@ private slots: void echoMode(); void passwordEchoOnEdit(); +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + void passwordEchoDelay(); +#endif + void maxLength_mask_data(); void maxLength_mask(); @@ -283,6 +289,9 @@ private slots: void bidiLogicalMovement_data(); void bidiLogicalMovement(); + void selectAndCursorPosition(); + void inputMethodSelection(); + protected slots: void editingFinished(); @@ -1679,6 +1688,51 @@ void tst_QLineEdit::passwordEchoOnEdit() testWidget->setEchoMode(QLineEdit::Normal); } +#ifdef QT_GUI_PASSWORD_ECHO_DELAY +void tst_QLineEdit::passwordEchoDelay() +{ + QStyleOptionFrameV2 opt; + QChar fillChar = testWidget->style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, testWidget); + + testWidget->setEchoMode(QLineEdit::Password); + testWidget->setFocus(); + testWidget->raise(); + QTRY_VERIFY(testWidget->hasFocus()); + + QTest::keyPress(testWidget, '0'); + QTest::keyPress(testWidget, '1'); + QTest::keyPress(testWidget, '2'); + QCOMPARE(testWidget->displayText(), QString(2, fillChar) + QLatin1Char('2')); + QTest::keyPress(testWidget, '3'); + QTest::keyPress(testWidget, '4'); + QCOMPARE(testWidget->displayText(), QString(4, fillChar) + QLatin1Char('4')); + QTest::keyPress(testWidget, Qt::Key_Backspace); + QCOMPARE(testWidget->displayText(), QString(4, fillChar)); + QTest::keyPress(testWidget, '4'); + QCOMPARE(testWidget->displayText(), QString(4, fillChar) + QLatin1Char('4')); + QTest::qWait(QT_GUI_PASSWORD_ECHO_DELAY); + QTRY_COMPARE(testWidget->displayText(), QString(5, fillChar)); + QTest::keyPress(testWidget, '5'); + QCOMPARE(testWidget->displayText(), QString(5, fillChar) + QLatin1Char('5')); + testWidget->clearFocus(); + QVERIFY(!testWidget->hasFocus()); + QCOMPARE(testWidget->displayText(), QString(6, fillChar)); + testWidget->setFocus(); + QTRY_VERIFY(testWidget->hasFocus()); + QCOMPARE(testWidget->displayText(), QString(6, fillChar)); + QTest::keyPress(testWidget, '6'); + QCOMPARE(testWidget->displayText(), QString(6, fillChar) + QLatin1Char('6')); + + QInputMethodEvent ev; + ev.setCommitString(QLatin1String("7")); + QApplication::sendEvent(testWidget, &ev); + QCOMPARE(testWidget->displayText(), QString(7, fillChar) + QLatin1Char('7')); + + // restore clean state + testWidget->setEchoMode(QLineEdit::Normal); +} +#endif + void tst_QLineEdit::maxLength_mask_data() { QTest::addColumn("mask"); @@ -3820,5 +3874,38 @@ void tst_QLineEdit::bidiLogicalMovement() } while (moved && i >= 0); } +void tst_QLineEdit::selectAndCursorPosition() +{ + testWidget->setText("This is a long piece of text"); + + testWidget->setSelection(0, 5); + QCOMPARE(testWidget->cursorPosition(), 5); + testWidget->setSelection(5, -5); + QCOMPARE(testWidget->cursorPosition(), 0); +} + +void tst_QLineEdit::inputMethodSelection() +{ + testWidget->setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + testWidget->setSelection(0,0); + QSignalSpy selectionSpy(testWidget, SIGNAL(selectionChanged())); + + QCOMPARE(selectionSpy.count(), 0); + QCOMPARE(testWidget->selectionStart(), -1); + + testWidget->setSelection(0,5); + + QCOMPARE(selectionSpy.count(), 1); + QCOMPARE(testWidget->selectionStart(), 0); + + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 12, 5, QVariant()); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(testWidget, &event); + + QCOMPARE(selectionSpy.count(), 2); + QCOMPARE(testWidget->selectionStart(), 12); +} + QTEST_MAIN(tst_QLineEdit) #include "tst_qlineedit.moc" diff --git a/tests/auto/qmessagebox/qmessagebox.pro b/tests/auto/qmessagebox/qmessagebox.pro index fe0e08aede..e3f6ddb1f6 100644 --- a/tests/auto/qmessagebox/qmessagebox.pro +++ b/tests/auto/qmessagebox/qmessagebox.pro @@ -7,5 +7,3 @@ INCLUDEPATH += . # Input SOURCES += tst_qmessagebox.cpp - -CONFIG+=insignificant_test diff --git a/tests/auto/qmessagebox/tst_qmessagebox.cpp b/tests/auto/qmessagebox/tst_qmessagebox.cpp index 0913454263..6b737681b1 100644 --- a/tests/auto/qmessagebox/tst_qmessagebox.cpp +++ b/tests/auto/qmessagebox/tst_qmessagebox.cpp @@ -127,9 +127,7 @@ private slots: void shortcut(); void staticSourceCompat(); - void staticBinaryCompat(); void instanceSourceCompat(); - void instanceBinaryCompat(); void testSymbols(); void incorrectDefaultButton(); @@ -407,19 +405,6 @@ void tst_QMessageBox::about() #endif } -// Old message box enums -const int Old_Ok = 1; -const int Old_Cancel = 2; -const int Old_Yes = 3; -const int Old_No = 4; -const int Old_Abort = 5; -const int Old_Retry = 6; -const int Old_Ignore = 7; -const int Old_YesAll = 8; -const int Old_NoAll = 9; -const int Old_Default = 0x100; -const int Old_Escape = 0x200; - void tst_QMessageBox::staticSourceCompat() { int ret; @@ -508,74 +493,6 @@ void tst_QMessageBox::instanceSourceCompat() QCOMPARE(exec(&mb, Qt::ALT + Qt::Key_Z), 1); } -void tst_QMessageBox::staticBinaryCompat() -{ - int ret; - - // binary compat tests for < 4.2 - keyToSend = Qt::Key_Enter; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes, Old_No, 0); - int expectedButton = int(Old_Yes); -#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) - if (qobject_cast(qApp->style())) - expectedButton = int(Old_No); -#elif !defined(QT_NO_STYLE_CLEANLOOKS) - if (qobject_cast(qApp->style())) - expectedButton = int(Old_No); -#endif - QCOMPARE(ret, expectedButton); - QCOMPARE(keyToSend, -1); - - keyToSend = Qt::Key_Escape; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes | Old_Escape, Old_No, 0); - QCOMPARE(ret, int(Old_Yes)); - QCOMPARE(keyToSend, -1); - - keyToSend = Qt::Key_Enter; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes | Old_Default, Old_No, 0); - QCOMPARE(ret, int(Old_Yes)); - QCOMPARE(keyToSend, -1); - -#if 0 - keyToSend = Qt::Key_Escape; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes, Old_No | Old_Default, 0); - QCOMPARE(ret, -1); - QCOMPARE(keyToSend, -1); -#endif - - keyToSend = Qt::Key_Escape; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes | Old_Escape, Old_No | Old_Default, 0); - QCOMPARE(ret, Old_Yes); - QCOMPARE(keyToSend, -1); - - keyToSend = Qt::Key_Escape; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes | Old_Default, Old_No | Old_Escape, 0); - QCOMPARE(ret, Old_No); - QCOMPARE(keyToSend, -1); - -} - -void tst_QMessageBox::instanceBinaryCompat() -{ - QMessageBox mb("Application name here", - "Saving the file will overwrite the original file on the disk.\n" - "Do you really want to save?", - QMessageBox::Information, - Old_Yes | Old_Default, - Old_No, - Old_Cancel | Old_Escape); - mb.setButtonText(Old_Yes, "Save"); - mb.setButtonText(Old_No, "Discard"); - QCOMPARE(exec(&mb, Qt::Key_Enter), int(Old_Yes)); - QCOMPARE(exec(&mb, Qt::Key_Escape), int(Old_Cancel)); -} - void tst_QMessageBox::testSymbols() { return; diff --git a/tests/auto/qmutex/tst_qmutex.cpp b/tests/auto/qmutex/tst_qmutex.cpp index 5fed6bb44e..7ad6a98a4d 100644 --- a/tests/auto/qmutex/tst_qmutex.cpp +++ b/tests/auto/qmutex/tst_qmutex.cpp @@ -65,6 +65,7 @@ private slots: void stressTest(); void tryLockRace(); void qtbug16115_trylock(); + void moreStress(); }; static const int iterations = 100; @@ -83,6 +84,8 @@ QMutex normalMutex, recursiveMutex(QMutex::Recursive); QSemaphore testsTurn; QSemaphore threadsTurn; +enum { waitTime = 100 }; + void tst_QMutex::tryLock() { // test non-recursive mutex @@ -109,18 +112,18 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); QTime timer; timer.start(); - QVERIFY(!normalMutex.tryLock(1000)); - QVERIFY(timer.elapsed() >= 1000); + QVERIFY(!normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); testsTurn.release(); threadsTurn.acquire(); timer.start(); - QVERIFY(normalMutex.tryLock(1000)); - QVERIFY(timer.elapsed() <= 1000); + QVERIFY(normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() <= waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); timer.start(); - QVERIFY(!normalMutex.tryLock(1000)); - QVERIFY(timer.elapsed() >= 1000); + QVERIFY(!normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); testsTurn.release(); @@ -132,7 +135,7 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); timer.start(); QVERIFY(normalMutex.tryLock(0)); - QVERIFY(timer.elapsed() < 1000); + QVERIFY(timer.elapsed() < waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); QVERIFY(!normalMutex.tryLock(0)); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); @@ -158,13 +161,13 @@ void tst_QMutex::tryLock() normalMutex.unlock(); threadsTurn.release(); - // thread can't acquire lock, timeout = 1000 + // thread can't acquire lock, timeout = waitTime testsTurn.acquire(); normalMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); threadsTurn.release(); - // thread can acquire lock, timeout = 1000 + // thread can acquire lock, timeout = waitTime testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); @@ -215,17 +218,17 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); QTime timer; timer.start(); - QVERIFY(!recursiveMutex.tryLock(1000)); - QVERIFY(timer.elapsed() >= 1000); + QVERIFY(!recursiveMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); QVERIFY(!recursiveMutex.tryLock(0)); testsTurn.release(); threadsTurn.acquire(); timer.start(); - QVERIFY(recursiveMutex.tryLock(1000)); - QVERIFY(timer.elapsed() <= 1000); + QVERIFY(recursiveMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() <= waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - QVERIFY(recursiveMutex.tryLock(1000)); + QVERIFY(recursiveMutex.tryLock(waitTime)); QVERIFY(lockCount.testAndSetRelaxed(1, 2)); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); @@ -241,7 +244,7 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); timer.start(); QVERIFY(recursiveMutex.tryLock(0)); - QVERIFY(timer.elapsed() < 1000); + QVERIFY(timer.elapsed() < waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); QVERIFY(recursiveMutex.tryLock(0)); QVERIFY(lockCount.testAndSetRelaxed(1, 2)); @@ -274,7 +277,7 @@ void tst_QMutex::tryLock() recursiveMutex.unlock(); threadsTurn.release(); - // thread can't acquire lock, timeout = 1000 + // thread can't acquire lock, timeout = waitTime testsTurn.acquire(); recursiveMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); @@ -282,7 +285,7 @@ void tst_QMutex::tryLock() QVERIFY(lockCount.testAndSetRelaxed(1, 2)); threadsTurn.release(); - // thread can acquire lock, timeout = 1000 + // thread can acquire lock, timeout = waitTime testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); @@ -436,7 +439,8 @@ void tst_QMutex::lock_unlock_locked_tryLock() } } -enum { one_minute = 60 * 1000, threadCount = 10 }; +enum { one_minute = 6 * 1000, //not really one minute, but else it is too long. + threadCount = 10 }; class StressTestThread : public QThread { @@ -497,7 +501,7 @@ public: do { if (mutex.tryLock()) mutex.unlock(); - } while (t.elapsed() < 20000); + } while (t.elapsed() < one_minute/2); } }; QMutex TryLockRaceThread::mutex; @@ -534,7 +538,7 @@ void tst_QMutex::qtbug16115_trylock() TrylockThread(QMutex &mut) : mut(mut) {} QMutex &mut; void run() { - for (int i = 0; i < 1000000; ++i) { + for (int i = 0; i < 100000; ++i) { if (mut.tryLock(0)) { if ((++qtbug16115_trylock_counter) != 1) ++qtbug16115_failure_count; @@ -553,7 +557,7 @@ void tst_QMutex::qtbug16115_trylock() t2.start(); t3.start(); - for (int i = 0; i < 1000000; ++i) { + for (int i = 0; i < 100000; ++i) { mut.lock(); if ((++qtbug16115_trylock_counter) != 1) ++qtbug16115_failure_count; @@ -567,5 +571,70 @@ void tst_QMutex::qtbug16115_trylock() QCOMPARE(qtbug16115_failure_count, 0); } + +class MoreStressTestThread : public QThread +{ + QTime t; +public: + static QAtomicInt lockCount; + static QAtomicInt sentinel[threadCount]; + static QMutex mutex[threadCount]; + static QAtomicInt errorCount; + void start() + { + t.start(); + QThread::start(); + } + void run() + { + quint64 i = 0; + while (t.elapsed() < one_minute) { + i++; + uint nb = (i * 9 + lockCount * 13) % threadCount; + QMutexLocker locker(&mutex[nb]); + if (sentinel[nb]) errorCount.ref(); + if (sentinel[nb].fetchAndAddRelaxed(5)) errorCount.ref(); + if (!sentinel[nb].testAndSetRelaxed(5, 0)) errorCount.ref(); + if (sentinel[nb]) errorCount.ref(); + lockCount.ref(); + nb = (nb * 17 + i * 5 + lockCount * 3) % threadCount; + if (mutex[nb].tryLock()) { + if (sentinel[nb]) errorCount.ref(); + if (sentinel[nb].fetchAndAddRelaxed(16)) errorCount.ref(); + if (!sentinel[nb].testAndSetRelaxed(16, 0)) errorCount.ref(); + if (sentinel[nb]) errorCount.ref(); + lockCount.ref(); + mutex[nb].unlock(); + } + nb = (nb * 15 + i * 47 + lockCount * 31) % threadCount; + if (mutex[nb].tryLock(2)) { + if (sentinel[nb]) errorCount.ref(); + if (sentinel[nb].fetchAndAddRelaxed(53)) errorCount.ref(); + if (!sentinel[nb].testAndSetRelaxed(53, 0)) errorCount.ref(); + if (sentinel[nb]) errorCount.ref(); + lockCount.ref(); + mutex[nb].unlock(); + } + } + } +}; +QMutex MoreStressTestThread::mutex[threadCount]; +QAtomicInt MoreStressTestThread::lockCount; +QAtomicInt MoreStressTestThread::sentinel[threadCount]; +QAtomicInt MoreStressTestThread::errorCount = 0; + +void tst_QMutex::moreStress() +{ + MoreStressTestThread threads[threadCount]; + for (int i = 0; i < threadCount; ++i) + threads[i].start(); + QVERIFY(threads[0].wait(one_minute + 10000)); + for (int i = 1; i < threadCount; ++i) + QVERIFY(threads[i].wait(10000)); + qDebug("locked %d times", int(MoreStressTestThread::lockCount)); + QCOMPARE(int(MoreStressTestThread::errorCount), 0); +} + + QTEST_MAIN(tst_QMutex) #include "tst_qmutex.moc" diff --git a/tests/auto/qnetworkaddressentry/qnetworkaddressentry.pro b/tests/auto/qnetworkaddressentry/qnetworkaddressentry.pro index 7b968723cd..885dbf796c 100644 --- a/tests/auto/qnetworkaddressentry/qnetworkaddressentry.pro +++ b/tests/auto/qnetworkaddressentry/qnetworkaddressentry.pro @@ -4,5 +4,3 @@ SOURCES += tst_qnetworkaddressentry.cpp QT = core network symbian: TARGET.CAPABILITY = NetworkServices - -CONFIG+=insignificant_test diff --git a/tests/auto/qnetworkaddressentry/tst_qnetworkaddressentry.cpp b/tests/auto/qnetworkaddressentry/tst_qnetworkaddressentry.cpp index cf14aabb41..42b9af8dd3 100644 --- a/tests/auto/qnetworkaddressentry/tst_qnetworkaddressentry.cpp +++ b/tests/auto/qnetworkaddressentry/tst_qnetworkaddressentry.cpp @@ -97,7 +97,7 @@ void tst_QNetworkAddressEntry::prefixAndNetmask_data() // IPv4 set: QHostAddress ipv4(QHostAddress::LocalHost); - QTest::newRow("v4/0") << ipv4 << QHostAddress(QHostAddress::Any) << 0; + QTest::newRow("v4/0") << ipv4 << QHostAddress(QHostAddress::AnyIPv4) << 0; QTest::newRow("v4/32") << ipv4 << QHostAddress("255.255.255.255") << 32; QTest::newRow("v4/24") << ipv4 << QHostAddress("255.255.255.0") << 24; QTest::newRow("v4/23") << ipv4 << QHostAddress("255.255.254.0") << 23; diff --git a/tests/auto/qprocess/tst_qprocess.cpp b/tests/auto/qprocess/tst_qprocess.cpp index f54dfa3f68..9873c3e357 100644 --- a/tests/auto/qprocess/tst_qprocess.cpp +++ b/tests/auto/qprocess/tst_qprocess.cpp @@ -335,7 +335,7 @@ void tst_QProcess::crashTest() QSignalSpy spy(process, SIGNAL(error(QProcess::ProcessError))); QSignalSpy spy2(process, SIGNAL(finished(int, QProcess::ExitStatus))); - QVERIFY(process->waitForFinished(5000)); + QVERIFY(process->waitForFinished(30000)); QCOMPARE(spy.count(), 1); QCOMPARE(*static_cast(spy.at(0).at(0).constData()), QProcess::Crashed); @@ -372,7 +372,7 @@ void tst_QProcess::crashTest2() QObject::connect(process, SIGNAL(finished(int)), this, SLOT(exitLoopSlot())); - QTestEventLoop::instance().enterLoop(5); + QTestEventLoop::instance().enterLoop(30); if (QTestEventLoop::instance().timeout()) QFAIL("Failed to detect crash : operation timed out"); @@ -673,7 +673,7 @@ void tst_QProcess::exitStatus() for (int i = 0; i < processList.count(); ++i) { process->start(processList.at(i)); QVERIFY(process->waitForStarted(5000)); - QVERIFY(process->waitForFinished(5000)); + QVERIFY(process->waitForFinished(30000)); QCOMPARE(process->exitStatus(), exitStatus.at(i)); } diff --git a/tests/auto/qrawfont/tst_qrawfont.cpp b/tests/auto/qrawfont/tst_qrawfont.cpp index e0680c4257..eb78057b5e 100644 --- a/tests/auto/qrawfont/tst_qrawfont.cpp +++ b/tests/auto/qrawfont/tst_qrawfont.cpp @@ -47,7 +47,6 @@ class tst_QRawFont: public QObject { Q_OBJECT - #if !defined(QT_NO_RAWFONT) private slots: void invalidRawFont(); @@ -94,6 +93,11 @@ private slots: void rawFontSetPixelSize_data(); void rawFontSetPixelSize(); + +#if defined(Q_WS_X11) || defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + void multipleRawFontsFromData(); +#endif + #endif // QT_NO_RAWFONT }; @@ -843,6 +847,25 @@ void tst_QRawFont::rawFontSetPixelSize() QCOMPARE(rawFont.pixelSize(), 24.0); } +#if defined(Q_WS_X11) || defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) +void tst_QRawFont::multipleRawFontsFromData() +{ + QFile file(QString::fromLatin1(SRCDIR "testfont.ttf")); + QRawFont testFont; + if (file.open(QIODevice::ReadOnly)) { + testFont.loadFromData(file.readAll(), 11, QFont::PreferDefaultHinting); + file.close(); + } + file.setFileName(QLatin1String(SRCDIR "testfont_bold_italic.ttf")); + QRawFont testFontBoldItalic; + if (file.open(QIODevice::ReadOnly)) + testFontBoldItalic.loadFromData(file.readAll(), 11, QFont::PreferDefaultHinting); + + QVERIFY(testFont.familyName() != (testFontBoldItalic.familyName()) + || testFont.styleName() != (testFontBoldItalic.styleName())); +} +#endif + #endif // QT_NO_RAWFONT QTEST_MAIN(tst_QRawFont) diff --git a/tests/auto/qregexpvalidator/tst_qregexpvalidator.cpp b/tests/auto/qregexpvalidator/tst_qregexpvalidator.cpp index d8ef92a439..23cd5b1ef1 100644 --- a/tests/auto/qregexpvalidator/tst_qregexpvalidator.cpp +++ b/tests/auto/qregexpvalidator/tst_qregexpvalidator.cpp @@ -115,9 +115,12 @@ void tst_QRegExpValidator::validate() QFETCH( int, state ); QRegExpValidator rv( 0 ); + QSignalSpy spy(&rv, SIGNAL(regExpChanged(const QRegExp&))); + rv.setRegExp( QRegExp( rx ) ); int dummy; QCOMPARE( (int)rv.validate( value, dummy ), state ); + QCOMPARE(spy.count(), 1); } QTEST_MAIN(tst_QRegExpValidator) diff --git a/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp b/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp index cc4ab67d53..5f1a6211aa 100644 --- a/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp +++ b/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp @@ -92,6 +92,7 @@ private slots: void escapedTableName(); void whiteSpaceInIdentifiers(); void psqlSchemaTest(); + void selectAfterUpdate(); private: void dropTestTables( QSqlDatabase db ); @@ -1467,5 +1468,27 @@ void tst_QSqlRelationalTableModel::psqlSchemaTest() QVERIFY_SQL(model, select()); } +void tst_QSqlRelationalTableModel::selectAfterUpdate() +{ + QFETCH_GLOBAL(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + QSqlRelationalTableModel model(0, db); + model.setTable(reltest1); + model.setRelation(2, QSqlRelation(reltest2, "tid", "title")); + QVERIFY_SQL(model, select()); + QVERIFY(model.relationModel(2)->rowCount() == 2); + { + QSqlQuery q(db); + QVERIFY_SQL(q, exec("insert into " + reltest2 + " values(3, 'mrs')")); + model.relationModel(2)->select(); + } + QVERIFY(model.relationModel(2)->rowCount() == 3); + QVERIFY(model.setData(model.index(0,2), 3)); + QVERIFY(model.submitAll()); + QCOMPARE(model.data(model.index(0,2)), QVariant("mrs")); +} + QTEST_MAIN(tst_QSqlRelationalTableModel) #include "tst_qsqlrelationaltablemodel.moc" diff --git a/tests/auto/qsslcertificate/tst_qsslcertificate.cpp b/tests/auto/qsslcertificate/tst_qsslcertificate.cpp index 451465df0c..e0bc029c71 100644 --- a/tests/auto/qsslcertificate/tst_qsslcertificate.cpp +++ b/tests/auto/qsslcertificate/tst_qsslcertificate.cpp @@ -118,6 +118,9 @@ private slots: void subjectAndIssuerAttributes(); void verify(); + // helper for verbose test failure messages + QString toString(const QList&); + // ### add tests for certificate bundles (multiple certificates concatenated into a single // structure); both PEM and DER formatted #endif @@ -907,10 +910,16 @@ void tst_QSslCertificate::verify() QList errors; QList toVerify; + // Like QVERIFY, but be verbose about the content of `errors' when failing +#define VERIFY_VERBOSE(A) \ + QVERIFY2((A), \ + qPrintable(QString("errors: %1").arg(toString(errors))) \ + ) + // Empty chain is unspecified error errors = QSslCertificate::verify(toVerify); - QVERIFY(errors.count() == 1); - QVERIFY(errors[0] == QSslError(QSslError::UnspecifiedError)); + VERIFY_VERBOSE(errors.count() == 1); + VERIFY_VERBOSE(errors[0] == QSslError(QSslError::UnspecifiedError)); errors.clear(); // Verify a valid cert signed by a CA @@ -920,7 +929,8 @@ void tst_QSslCertificate::verify() toVerify = QSslCertificate::fromPath(SRCDIR "verify-certs/test-ocsp-good-cert.pem"); errors = QSslCertificate::verify(toVerify); - QVERIFY(errors.count() == 0); + QEXPECT_FAIL("", "QTBUG-20582 fails since ~5am, 27th July 2011", Continue); + VERIFY_VERBOSE(errors.count() == 0); errors.clear(); // Test a blacklisted certificate @@ -939,8 +949,8 @@ void tst_QSslCertificate::verify() // This one is expired and untrusted toVerify = QSslCertificate::fromPath(SRCDIR "more-certificates/cert-large-serial-number.pem"); errors = QSslCertificate::verify(toVerify); - QVERIFY(errors.contains(QSslError(QSslError::SelfSignedCertificate, toVerify[0]))); - QVERIFY(errors.contains(QSslError(QSslError::CertificateExpired, toVerify[0]))); + VERIFY_VERBOSE(errors.contains(QSslError(QSslError::SelfSignedCertificate, toVerify[0]))); + VERIFY_VERBOSE(errors.contains(QSslError(QSslError::CertificateExpired, toVerify[0]))); errors.clear(); toVerify.clear(); @@ -948,23 +958,38 @@ void tst_QSslCertificate::verify() toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-intermediate-not-ca-cert.pem").first(); toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-ocsp-good-cert.pem").first(); errors = QSslCertificate::verify(toVerify); - QVERIFY(errors.contains(QSslError(QSslError::InvalidCaCertificate, toVerify[1]))); + VERIFY_VERBOSE(errors.contains(QSslError(QSslError::InvalidCaCertificate, toVerify[1]))); toVerify.clear(); // This one is signed by a valid cert, and the signer is a valid CA toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-intermediate-is-ca-cert.pem").first(); toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-intermediate-ca-cert.pem").first(); errors = QSslCertificate::verify(toVerify); - QVERIFY(errors.length() == 0); + QEXPECT_FAIL("", "QTBUG-20582 fails since ~5am, 27th July 2011", Continue); + VERIFY_VERBOSE(errors.count() == 0); // Recheck the above with hostname validation errors = QSslCertificate::verify(toVerify, QLatin1String("example.com")); - QVERIFY(errors.length() == 0); + QEXPECT_FAIL("", "QTBUG-20582 fails since ~5am, 27th July 2011", Continue); + VERIFY_VERBOSE(errors.count() == 0); // Recheck the above with a bad hostname errors = QSslCertificate::verify(toVerify, QLatin1String("fail.example.com")); - QVERIFY(errors.contains(QSslError(QSslError::HostNameMismatch, toVerify[0]))); + VERIFY_VERBOSE(errors.contains(QSslError(QSslError::HostNameMismatch, toVerify[0]))); toVerify.clear(); + +#undef VERIFY_VERBOSE +} + +QString tst_QSslCertificate::toString(const QList& errors) +{ + QStringList errorStrings; + + foreach (const QSslError& error, errors) { + errorStrings.append(QLatin1String("\"") + error.errorString() + QLatin1String("\"")); + } + + return QLatin1String("[ ") + errorStrings.join(QLatin1String(", ")) + QLatin1String(" ]"); } #endif // QT_NO_OPENSSL diff --git a/tests/auto/qstring/tst_qstring.cpp b/tests/auto/qstring/tst_qstring.cpp index 8c725fa109..f7a725c164 100644 --- a/tests/auto/qstring/tst_qstring.cpp +++ b/tests/auto/qstring/tst_qstring.cpp @@ -5110,7 +5110,7 @@ void tst_QString::toUpperLower_icu() void tst_QString::literals() { -#if defined(QT_QSTRING_UNICODE_MARKER) && (defined(Q_COMPILER_LAMBDA) || defined(Q_CC_GNU)) +#if defined(QT_UNICODE_LITERAL) && (defined(Q_COMPILER_LAMBDA) || defined(Q_CC_GNU)) QString str(QStringLiteral("abcd")); QVERIFY(str.length() == 4); diff --git a/tests/auto/qstringbuilder1/stringbuilder.cpp b/tests/auto/qstringbuilder1/stringbuilder.cpp index de7ad656e4..4d453b0585 100644 --- a/tests/auto/qstringbuilder1/stringbuilder.cpp +++ b/tests/auto/qstringbuilder1/stringbuilder.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include + #define LITERAL "some literal" #define LITERAL_LEN (sizeof(LITERAL)-1) #define LITERAL_EXTRA "some literal" "EXTRA" @@ -48,6 +50,12 @@ #define UTF8_LITERAL_LEN (sizeof(UTF8_LITERAL)-1) #define UTF8_LITERAL_EXTRA "s\xc3\xb6m\xc3\xab l\xc3\xaft\xc3\xabr\xc3\xa4l" "EXTRA" +#ifdef Q_COMPILER_UNICODE_STRINGS +// "some literal", but replacing all vocals by their umlauted UTF-8 string :) +#define UNICODE_LITERAL u"s\u00f6m\u00eb l\u00eft\u00ebr\u00e4l" +#define UNICODE_LITERAL_LEN ((sizeof(UNICODE_LITERAL) - 1) / 2) +#define UNICODE_LITERAL_EXTRA u"s\u00f6m\u00eb l\u00eft\u00ebr\u00e4l" "EXTRA" +#endif //fix for gcc4.0: if the operator+ does not exist without QT_USE_FAST_OPERATOR_PLUS #ifndef QT_USE_FAST_CONCATENATION @@ -68,6 +76,7 @@ void runScenario() QStringRef stringref(&string, 2, 10); QLatin1Char achar('c'); QString r2(QLatin1String(LITERAL LITERAL)); + QString r3 = QString::fromUtf8(UTF8_LITERAL UTF8_LITERAL); QString r; r = l1literal Q l1literal; @@ -80,10 +89,23 @@ void runScenario() QCOMPARE(r, r2); r = string P l1string; QCOMPARE(r, r2); + r = string Q QStringLiteral(LITERAL); + QCOMPARE(r, r2); + r = QStringLiteral(LITERAL) Q string; + QCOMPARE(r, r2); + r = l1string Q QStringLiteral(LITERAL); + QCOMPARE(r, r2); r = string + achar; QCOMPARE(r, QString(string P achar)); r = achar + string; QCOMPARE(r, QString(achar P string)); + +#ifdef Q_COMPILER_UNICODE_STRINGS + r = QStringLiteral(UNICODE_LITERAL); + r = r Q QStringLiteral(UNICODE_LITERAL); + QCOMPARE(r, r3); +#endif + #ifndef QT_NO_CAST_FROM_ASCII r = string P LITERAL; QCOMPARE(r, r2); @@ -96,6 +118,11 @@ void runScenario() r = string P ba; QCOMPARE(r, r2); + r = string P QByteArrayLiteral(LITERAL); + QCOMPARE(r, r2); + r = QByteArrayLiteral(LITERAL) P string; + QCOMPARE(r, r2); + static const char badata[] = LITERAL_EXTRA; ba = QByteArray::fromRawData(badata, LITERAL_LEN); r = ba P string; @@ -109,24 +136,23 @@ void runScenario() QCOMPARE(QTextCodec::codecForCStrings()->name(), QByteArray("UTF-8")); string = QString::fromUtf8(UTF8_LITERAL); - r2 = QString::fromUtf8(UTF8_LITERAL UTF8_LITERAL); ba = UTF8_LITERAL; r = string P UTF8_LITERAL; - QCOMPARE(r.size(), r2.size()); - QCOMPARE(r, r2); + QCOMPARE(r.size(), r3.size()); + QCOMPARE(r, r3); r = UTF8_LITERAL P string; - QCOMPARE(r, r2); + QCOMPARE(r, r3); r = ba P string; - QCOMPARE(r, r2); + QCOMPARE(r, r3); r = string P ba; - QCOMPARE(r, r2); + QCOMPARE(r, r3); ba = QByteArray::fromRawData(UTF8_LITERAL_EXTRA, UTF8_LITERAL_LEN); r = ba P string; - QCOMPARE(r, r2); + QCOMPARE(r, r3); r = string P ba; - QCOMPARE(r, r2); + QCOMPARE(r, r3); ba = QByteArray(); // empty r = ba P string; @@ -152,6 +178,11 @@ void runScenario() QByteArray superba = ba P ba P LITERAL; QCOMPARE(superba, QByteArray(LITERAL LITERAL LITERAL)); + ba = QByteArrayLiteral(LITERAL); + QCOMPARE(ba, QByteArray(LITERAL)); + superba = ba P QByteArrayLiteral(LITERAL) P LITERAL; + QCOMPARE(superba, QByteArray(LITERAL LITERAL LITERAL)); + QByteArray testWith0 = ba P "test\0with\0zero" P ba; QCOMPARE(testWith0, QByteArray(LITERAL "test" LITERAL)); diff --git a/tests/auto/qtconcurrentfilter/qtconcurrentfilter.pro b/tests/auto/qtconcurrentfilter/qtconcurrentfilter.pro index ee2b77d63c..62d4908e69 100644 --- a/tests/auto/qtconcurrentfilter/qtconcurrentfilter.pro +++ b/tests/auto/qtconcurrentfilter/qtconcurrentfilter.pro @@ -3,4 +3,4 @@ DEFINES += QT_STRICT_ITERATORS SOURCES += tst_qtconcurrentfilter.cpp QT = core CONFIG += parallel_test -CONFIG += parallel_test +linux*:CONFIG += insignificant_test diff --git a/tests/auto/qtcpserver/tst_qtcpserver.cpp b/tests/auto/qtcpserver/tst_qtcpserver.cpp index b566e5cebd..b72e61f374 100644 --- a/tests/auto/qtcpserver/tst_qtcpserver.cpp +++ b/tests/auto/qtcpserver/tst_qtcpserver.cpp @@ -575,7 +575,7 @@ void tst_QTcpServer::addressReusable() socket.connectToHost(QHostAddress::LocalHost, 49199); QVERIFY(socket.waitForConnected(5000)); - QVERIFY(process.waitForFinished(5000)); + QVERIFY(process.waitForFinished(30000)); // Give the system some time. QTest::qSleep(10); diff --git a/tests/auto/qtextedit/tst_qtextedit.cpp b/tests/auto/qtextedit/tst_qtextedit.cpp index 67c610b21a..f10879d284 100644 --- a/tests/auto/qtextedit/tst_qtextedit.cpp +++ b/tests/auto/qtextedit/tst_qtextedit.cpp @@ -207,6 +207,8 @@ private slots: void bidiLogicalMovement_data(); void bidiLogicalMovement(); + void inputMethodSelection(); + private: void createSelection(); int blockCount() const; @@ -2365,5 +2367,30 @@ void tst_QTextEdit::bidiLogicalMovement() } while (moved && i >= 0); } +void tst_QTextEdit::inputMethodSelection() +{ + ed->setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + + QSignalSpy selectionSpy(ed, SIGNAL(selectionChanged())); + QTextCursor cursor = ed->textCursor(); + cursor.setPosition(0); + cursor.setPosition(5, QTextCursor::KeepAnchor); + ed->setTextCursor(cursor); + + QCOMPARE(selectionSpy.count(), 1); + QCOMPARE(ed->textCursor().selectionStart(), 0); + QCOMPARE(ed->textCursor().selectionEnd(), 5); + + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 12, 5, QVariant()); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(ed, &event); + + QCOMPARE(selectionSpy.count(), 2); + QCOMPARE(ed->textCursor().selectionStart(), 12); + QCOMPARE(ed->textCursor().selectionEnd(), 17); +} + + QTEST_MAIN(tst_QTextEdit) #include "tst_qtextedit.moc" diff --git a/tests/auto/qtextscriptengine/qtextscriptengine.pro b/tests/auto/qtextscriptengine/qtextscriptengine.pro index 1bd80d35b6..0f5076e2ed 100644 --- a/tests/auto/qtextscriptengine/qtextscriptengine.pro +++ b/tests/auto/qtextscriptengine/qtextscriptengine.pro @@ -5,5 +5,3 @@ QT += core-private gui-private HEADERS += SOURCES += tst_qtextscriptengine.cpp INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src - -CONFIG+=insignificant_test diff --git a/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp b/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp index 6cbff362bc..cbed675cb7 100644 --- a/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp +++ b/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp @@ -76,9 +76,6 @@ //TESTED_CLASS= //TESTED_FILES= gui/text/qscriptengine.cpp -// This test depends on the fonts in the following package being installed: -// http://people.freedesktop.org/~hausmann/harfbuzz-test-fonts-0.1.tar.bz2 - class tst_QTextScriptEngine : public QObject { Q_OBJECT @@ -89,6 +86,7 @@ public: public slots: + void initTestCase(); void init(); void cleanup(); private slots: @@ -111,9 +109,13 @@ private slots: void mirroredChars_data(); void mirroredChars(); + +private: + bool haveTestFonts; }; tst_QTextScriptEngine::tst_QTextScriptEngine() + : haveTestFonts(qgetenv("QT_HAVE_TEST_FONTS") == QByteArray("1")) { } @@ -121,6 +123,21 @@ tst_QTextScriptEngine::~tst_QTextScriptEngine() { } +void tst_QTextScriptEngine::initTestCase() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + qWarning( + "Some of these tests depend on the internals of some test fonts which are not freely " + "distributable.\n" + "These tests will be skipped.\n" + "If you have the fonts available, set QT_HAVE_TEST_FONTS=1 in your environment and " + "run the test again." + ); + } +#endif +} + void tst_QTextScriptEngine::init() { } @@ -184,6 +201,10 @@ static bool shaping( const QFont &f, const ShapeTable *s) void tst_QTextScriptEngine::devanagari() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Devanagari).contains("Raghindi")) { QFont f("Raghindi"); @@ -233,7 +254,7 @@ void tst_QTextScriptEngine::devanagari() ++s; } } else { - QSKIP("couln't find Raghindi", SkipAll); + QSKIP("couldn't find Raghindi", SkipAll); } } @@ -296,6 +317,10 @@ void tst_QTextScriptEngine::devanagari() void tst_QTextScriptEngine::bengali() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Bengali).contains("Akaash")) { QFont f("Akaash"); @@ -403,7 +428,7 @@ void tst_QTextScriptEngine::bengali() ++s; } } else { - QSKIP("couln't find Akaash", SkipAll); + QSKIP("couldn't find Akaash", SkipAll); } } { @@ -508,7 +533,7 @@ void tst_QTextScriptEngine::bengali() ++s; } } else { - QSKIP("couln't find Mukti", SkipAll); + QSKIP("couldn't find Mukti", SkipAll); } } { @@ -536,7 +561,7 @@ void tst_QTextScriptEngine::bengali() ++s; } } else { - QSKIP("couln't find Likhan", SkipAll); + QSKIP("couldn't find Likhan", SkipAll); } } #else @@ -547,6 +572,10 @@ void tst_QTextScriptEngine::bengali() void tst_QTextScriptEngine::gurmukhi() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Gurmukhi).contains("Lohit Punjabi")) { QFont f("Lohit Punjabi"); @@ -563,7 +592,7 @@ void tst_QTextScriptEngine::gurmukhi() ++s; } } else { - QSKIP("couln't find Lohit Punjabi", SkipAll); + QSKIP("couldn't find Lohit Punjabi", SkipAll); } } #endif @@ -572,6 +601,10 @@ void tst_QTextScriptEngine::gurmukhi() void tst_QTextScriptEngine::oriya() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Oriya).contains("utkal")) { QFont f("utkal"); @@ -600,7 +633,7 @@ void tst_QTextScriptEngine::oriya() ++s; } } else { - QSKIP("couln't find utkal", SkipAll); + QSKIP("couldn't find utkal", SkipAll); } } #else @@ -612,6 +645,10 @@ void tst_QTextScriptEngine::oriya() void tst_QTextScriptEngine::tamil() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Tamil).contains("AkrutiTml1")) { QFont f("AkrutiTml1"); @@ -677,7 +714,7 @@ void tst_QTextScriptEngine::tamil() ++s; } } else { - QSKIP("couln't find AkrutiTml1", SkipAll); + QSKIP("couldn't find AkrutiTml1", SkipAll); } } #else @@ -689,6 +726,10 @@ void tst_QTextScriptEngine::tamil() void tst_QTextScriptEngine::telugu() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Telugu).contains("Pothana2000")) { QFont f("Pothana2000"); @@ -725,7 +766,7 @@ void tst_QTextScriptEngine::telugu() ++s; } } else { - QSKIP("couln't find Pothana2000", SkipAll); + QSKIP("couldn't find Pothana2000", SkipAll); } } #else @@ -772,7 +813,7 @@ void tst_QTextScriptEngine::kannada() ++s; } } else { - QSKIP("couln't find Sampige", SkipAll); + QSKIP("couldn't find Sampige", SkipAll); } } { @@ -803,7 +844,7 @@ void tst_QTextScriptEngine::kannada() ++s; } } else { - QSKIP("couln't find Tunga", SkipAll); + QSKIP("couldn't find Tunga", SkipAll); } } #else @@ -816,6 +857,10 @@ void tst_QTextScriptEngine::kannada() void tst_QTextScriptEngine::malayalam() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Malayalam).contains("AkrutiMal2")) { QFont f("AkrutiMal2"); @@ -864,7 +909,7 @@ void tst_QTextScriptEngine::malayalam() ++s; } } else { - QSKIP("couln't find AkrutiMal2", SkipAll); + QSKIP("couldn't find AkrutiMal2", SkipAll); } } { @@ -892,7 +937,7 @@ void tst_QTextScriptEngine::malayalam() ++s; } } else { - QSKIP("couln't find Rachana", SkipAll); + QSKIP("couldn't find Rachana", SkipAll); } } @@ -904,6 +949,10 @@ void tst_QTextScriptEngine::malayalam() void tst_QTextScriptEngine::sinhala() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Sinhala).contains("Malithi Web")) { QFont f("Malithi Web"); @@ -930,7 +979,7 @@ void tst_QTextScriptEngine::sinhala() ++s; } } else { - QSKIP("couln't find Malithi Web", SkipAll); + QSKIP("couldn't find Malithi Web", SkipAll); } } #else @@ -942,6 +991,10 @@ void tst_QTextScriptEngine::sinhala() void tst_QTextScriptEngine::khmer() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Khmer).contains("Khmer OS")) { QFont f("Khmer OS"); @@ -974,7 +1027,7 @@ void tst_QTextScriptEngine::khmer() ++s; } } else { - QSKIP("couln't find Khmer OS", SkipAll); + QSKIP("couldn't find Khmer OS", SkipAll); } } #else @@ -985,6 +1038,10 @@ void tst_QTextScriptEngine::khmer() void tst_QTextScriptEngine::linearB() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Any).contains("Penuturesu")) { QFont f("Penuturesu"); @@ -1001,7 +1058,7 @@ void tst_QTextScriptEngine::linearB() ++s; } } else { - QSKIP("couln't find Penuturesu", SkipAll); + QSKIP("couldn't find Penuturesu", SkipAll); } } #else @@ -1060,6 +1117,10 @@ static bool decomposedShaping( const QFont &f, const QChar &ch) void tst_QTextScriptEngine::greek() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Any).contains("DejaVu Sans")) { QFont f("DejaVu Sans"); @@ -1075,7 +1136,7 @@ void tst_QTextScriptEngine::greek() QVERIFY( decomposedShaping(f, QChar(uc)) ); } } else { - QSKIP("couln't find DejaVu Sans", SkipAll); + QSKIP("couldn't find DejaVu Sans", SkipAll); } } @@ -1111,7 +1172,7 @@ void tst_QTextScriptEngine::greek() ++s; } } else { - QSKIP("couln't find SBL_grk", SkipAll); + QSKIP("couldn't find SBL_grk", SkipAll); } } #else diff --git a/tests/auto/qwaitcondition/tst_qwaitcondition.cpp b/tests/auto/qwaitcondition/tst_qwaitcondition.cpp index c677d17fbe..6545df9189 100644 --- a/tests/auto/qwaitcondition/tst_qwaitcondition.cpp +++ b/tests/auto/qwaitcondition/tst_qwaitcondition.cpp @@ -491,7 +491,7 @@ void tst_QWaitCondition::wakeOne() for (int y = 0; y < ThreadCount; ++y) { if (thread_exited[y]) continue; - if (thread[y].wait(exited > 0 ? 3 : 1000)) { + if (thread[y].wait(exited > 0 ? 10 : 1000)) { thread_exited[y] = TRUE; ++exited; } @@ -535,7 +535,7 @@ void tst_QWaitCondition::wakeOne() for (int y = 0; y < ThreadCount; ++y) { if (thread_exited[y]) continue; - if (rwthread[y].wait(exited > 0 ? 3 : 1000)) { + if (rwthread[y].wait(exited > 0 ? 10 : 1000)) { thread_exited[y] = TRUE; ++exited; } @@ -587,7 +587,7 @@ void tst_QWaitCondition::wakeOne() for (int y = 0; y < ThreadCount; ++y) { if (thread_exited[y]) continue; - if (thread[y].wait(exited > 0 ? 3 : 1000)) { + if (thread[y].wait(exited > 0 ? 10 : 1000)) { thread_exited[y] = TRUE; ++exited; } @@ -633,7 +633,7 @@ void tst_QWaitCondition::wakeOne() for (int y = 0; y < ThreadCount; ++y) { if (thread_exited[y]) continue; - if (rwthread[y].wait(exited > 0 ? 3 : 1000)) { + if (rwthread[y].wait(exited > 0 ? 10 : 1000)) { thread_exited[y] = TRUE; ++exited; } diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index 05a15750c1..05e184d0c2 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -151,7 +151,6 @@ void tst_QMutex::noThread_data() QTest::addColumn("t"); QTest::newRow("noLock") << 1; - QTest::newRow("QMutexInline") << 2; QTest::newRow("QMutex") << 3; QTest::newRow("QMutexLocker") << 4; } @@ -172,16 +171,6 @@ void tst_QMutex::noThread() } } break; - case 2: - QBENCHMARK { - count = 0; - for (int i = 0; i < N; i++) { - mtx.lockInline(); - count++; - mtx.unlockInline(); - } - } - break; case 3: QBENCHMARK { count = 0; diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index cde4ddd833..e980755305 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -221,6 +221,12 @@ Configure::Configure(int& argc, char** argv) createpackage_bat.close(); } + QFile configtests(buildPath + "/bin/qtmodule-configtests"); + if (configtests.open(QFile::WriteOnly)) { + QTextStream stream(&configtests); + stream << "#!/usr/bin/perl -w" << endl + << "require \"" << sourcePath + "/bin/qtmodule-configtests\";" << endl; + } // For Windows CE and shadow builds we need to copy these to the // build directory. QFile::copy(sourcePath + "/bin/setcepaths.bat" , buildPath + "/bin/setcepaths.bat");