diff --git a/MANIFEST b/MANIFEST
index 86390ed37..02faef124 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -75,6 +75,7 @@ t/gcode.t
 t/geometry.t
 t/layers.t
 t/loops.t
+t/perimeters.t
 t/polyclip.t
 t/print.t
 t/retraction.t
diff --git a/lib/Slic3r/ExtrusionPath/Collection.pm b/lib/Slic3r/ExtrusionPath/Collection.pm
index 5a4af96de..88cc12528 100644
--- a/lib/Slic3r/ExtrusionPath/Collection.pm
+++ b/lib/Slic3r/ExtrusionPath/Collection.pm
@@ -14,7 +14,7 @@ sub first_point {
 
 sub chained_path {
     my $self = shift;
-    my ($start_near) = @_;
+    my ($start_near, $no_reverse) = @_;
     
     return @{$self->paths} if $self->no_sort;
     
@@ -26,7 +26,7 @@ sub chained_path {
         polylines => [ map $_->polyline, @paths ],
     );
     
-    return $collection->chained_path($start_near, \@paths);
+    return $collection->chained_path($start_near, \@paths, $no_reverse);
 }
 
 sub cleanup {
diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm
index f1eada2d0..4dd4587d6 100644
--- a/lib/Slic3r/GCode.pm
+++ b/lib/Slic3r/GCode.pm
@@ -51,7 +51,7 @@ sub _build_speeds {
 my %role_speeds = (
     &EXTR_ROLE_PERIMETER                    => 'perimeter',
     &EXTR_ROLE_EXTERNAL_PERIMETER           => 'external_perimeter',
-    &EXTR_ROLE_OVERHANG_PERIMETER           => 'external_perimeter',
+    &EXTR_ROLE_OVERHANG_PERIMETER           => 'bridge',
     &EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER   => 'perimeter',
     &EXTR_ROLE_FILL                         => 'infill',
     &EXTR_ROLE_SOLIDFILL                    => 'solid_infill',
@@ -176,13 +176,19 @@ sub extrude_loop {
         # inwards move consider the new actual starting point)
         @paths = Slic3r::ExtrusionPath::Collection
             ->new(paths => [@paths])
-            ->chained_path($last_pos);
+            ->chained_path($last_pos, 1);
     } else {
         push @paths, $extrusion_path;
     }
     
+    # apply the small perimeter speed
+    my %params = ();
+    if ($extrusion_path->is_perimeter && abs($extrusion_path->length) <= &Slic3r::SMALL_PERIMETER_LENGTH) {
+        $params{speed} = 'small_perimeter';
+    }
+    
     # extrude along the path
-    my $gcode = join '', map $self->extrude_path($_, $description), @paths;
+    my $gcode = join '', map $self->extrude_path($_, $description, %params), @paths;
     $self->wipe_path($extrusion_path->polyline);
     
     # make a little move inwards before leaving loop
@@ -211,23 +217,24 @@ sub extrude_loop {
 
 sub extrude_path {
     my $self = shift;
-    my ($path, $description, $recursive) = @_;
+    my ($path, $description, %params) = @_;
     
     $path = $path->unpack if $path->isa('Slic3r::ExtrusionPath::Packed');
     $path->simplify(&Slic3r::SCALED_RESOLUTION);
     
     # detect arcs
-    if ($self->config->gcode_arcs && !$recursive) {
+    if ($self->config->gcode_arcs && !$params{dont_detect_arcs}) {
         my $gcode = "";
         foreach my $arc_path ($path->detect_arcs) {
-            $gcode .= $self->extrude_path($arc_path, $description, 1);
+            $gcode .= $self->extrude_path($arc_path, $description, %params, dont_detect_arcs => 1);
         }
         return $gcode;
     }
     
     # go to first point of extrusion path
     my $gcode = "";
-    $gcode .= $self->travel_to($path->points->[0], $path->role, "move to first $description point");
+    $gcode .= $self->travel_to($path->points->[0], $path->role, "move to first $description point")
+        if !$self->last_pos || !$self->last_pos->coincides_with($path->points->[0]);
     
     # compensate retraction
     $gcode .= $self->unretract;
@@ -257,12 +264,7 @@ sub extrude_path {
     my $e = $self->extruder->e_per_mm3 * $area;
     
     # set speed
-    $self->speed( $role_speeds{$path->role} || die "Unknown role: " . $path->role );
-    if ($path->role == EXTR_ROLE_PERIMETER || $path->role == EXTR_ROLE_EXTERNAL_PERIMETER || $path->role == EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER) {
-        if (abs($path->length) <= &Slic3r::SMALL_PERIMETER_LENGTH) {
-            $self->speed('small_perimeter');
-        }
-    }
+    $self->speed( $params{speed} || $role_speeds{$path->role} || die "Unknown role: " . $path->role );
     
     # extrude arc or line
     my $path_length = 0;
diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm
index 50d3c5523..43a0917c5 100644
--- a/lib/Slic3r/Polyline.pm
+++ b/lib/Slic3r/Polyline.pm
@@ -221,7 +221,7 @@ has 'polylines' => (is => 'ro', default => sub { [] });
 # Note that our polylines will be reversed in place when necessary.
 sub chained_path {
     my $self = shift;
-    my ($start_near, $items) = @_;
+    my ($start_near, $items, $no_reverse) = @_;
     
     $items ||= $self->polylines;
     my %items_map = map { $self->polylines->[$_] => $items->[$_] } 0 .. $#{$self->polylines};
@@ -229,7 +229,9 @@ sub chained_path {
     
     my @paths = ();
     my $start_at;
-    my $endpoints = [ map { $_->[0], $_->[-1] } @my_paths ];
+    my $endpoints = $no_reverse
+        ? [ map { $_->[0], $_->[0]  } @my_paths ]
+        : [ map { $_->[0], $_->[-1] } @my_paths ];
     while (@my_paths) {
         # find nearest point
         my $start_index = $start_near
@@ -237,7 +239,7 @@ sub chained_path {
             : 0;
 
         my $path_index = int($start_index/2);
-        if ($start_index%2) { # index is end so reverse to make it the start
+        if ($start_index % 2 && !$no_reverse) { # index is end so reverse to make it the start
             $my_paths[$path_index]->reverse;
         }
         push @paths, splice @my_paths, $path_index, 1;
diff --git a/lib/Slic3r/Test.pm b/lib/Slic3r/Test.pm
index f645e3821..89a3ed7de 100644
--- a/lib/Slic3r/Test.pm
+++ b/lib/Slic3r/Test.pm
@@ -34,6 +34,13 @@ sub model {
         $facets = [
             [0,1,2],[2,1,3],[1,0,4],[5,1,4],[4,0,2],[6,4,2],[7,6,2],[8,9,7],[9,6,7],[2,3,7],[7,3,10],[1,5,3],[3,5,11],[11,12,13],[11,13,3],[3,13,10],[5,4,6],[11,5,6],[6,9,11],[11,9,12],[12,9,8],[13,12,8],[8,7,10],[13,8,10]
         ],
+    } elsif ($model_name eq 'overhang') {
+        $vertices = [
+            [1364.68505859375,614.398010253906,20.002498626709],[1389.68505859375,614.398010253906,20.002498626709],[1377.18505859375,589.398986816406,20.002498626709],[1389.68505859375,589.398986816406,20.002498626709],[1389.68505859375,564.398986816406,20.0014991760254],[1364.68505859375,589.398986816406,20.002498626709],[1364.68505859375,564.398986816406,20.0014991760254],[1360.93505859375,589.398986816406,17.0014991760254],[1360.93505859375,585.64697265625,17.0014991760254],[1357.18505859375,564.398986816406,17.0014991760254],[1364.68505859375,589.398986816406,17.0014991760254],[1364.68505859375,571.899963378906,17.0014991760254],[1364.68505859375,564.398986816406,17.0014991760254],[1348.43603515625,564.398986816406,17.0014991760254],[1352.80908203125,589.398986816406,17.0014991760254],[1357.18408203125,589.398986816406,17.0014991760254],[1357.18310546875,614.398010253906,17.0014991760254],[1364.68505859375,606.89599609375,17.0014991760254],[1364.68505859375,614.398010253906,17.0014991760254],[1352.18603515625,564.398986816406,20.0014991760254],[1363.65405273438,589.398986816406,23.3004989624023],[1359.46704101562,589.398986816406,23.3004989624023],[1358.37109375,564.398986816406,23.3004989624023],[1385.56103515625,564.398986816406,23.3004989624023],[1373.06311035156,589.398986816406,23.3004989624023],[1368.80810546875,564.398986816406,23.3004989624023],[1387.623046875,589.398986816406,23.3004989624023],[1387.623046875,585.276000976562,23.3004989624023],[1389.68505859375,589.398986816406,23.3004989624023],[1389.68505859375,572.64599609375,23.3004989624023],[1389.68505859375,564.398986816406,23.3004989624023],[1367.77709960938,589.398986816406,23.3004989624023],[1366.7470703125,564.398986816406,23.3004989624023],[1354.31201171875,589.398986816406,23.3004989624023],[1352.18603515625,564.398986816406,23.3004989624023],[1389.68505859375,614.398010253906,23.3004989624023],[1377.31701660156,614.398010253906,23.3004989624023],[1381.43908691406,589.398986816406,23.3004989624023],[1368.80700683594,614.398010253906,23.3004989624023],[1368.80810546875,589.398986816406,23.3004989624023],[1356.43908691406,614.398010253906,23.3004989624023],[1357.40502929688,589.398986816406,23.3004989624023],[1360.56201171875,614.398010253906,23.3004989624023],[1348.705078125,614.398010253906,23.3004989624023],[1350.44506835938,589.398986816406,23.3004989624023],[1389.68505859375,606.153015136719,23.3004989624023],[1347.35205078125,589.398986816406,23.3004989624023],[1346.56005859375,589.398986816406,23.3004989624023],[1346.56005859375,594.159912109375,17.0014991760254],[1346.56005859375,589.398986816406,17.0014991760254],[1346.56005859375,605.250427246094,23.3004989624023],[1346.56005859375,614.398010253906,23.3004989624023],[1346.56005859375,614.398010253906,20.8258285522461],[1346.56005859375,614.398010253906,17.0014991760254],[1346.56005859375,564.398986816406,19.10133934021],[1346.56005859375,567.548583984375,23.3004989624023],[1346.56005859375,564.398986816406,17.0020332336426],[1346.56005859375,564.398986816406,23.0018501281738],[1346.56005859375,564.398986816406,23.3004989624023],[1346.56005859375,575.118957519531,17.0014991760254],[1346.56005859375,574.754028320312,23.3004989624023]
+        ];
+        $facets = [
+            [0,1,2],[2,3,4],[2,5,0],[4,6,2],[2,6,5],[2,1,3],[7,8,9],[10,9,8],[11,9,10],[12,9,11],[9,13,14],[7,15,16],[10,17,0],[10,0,5],[12,11,6],[18,16,0],[6,19,13],[6,13,9],[9,12,6],[17,18,0],[11,10,5],[11,5,6],[14,16,15],[17,7,18],[16,18,7],[14,15,9],[7,9,15],[7,17,8],[10,8,17],[20,21,22],[23,24,25],[26,23,27],[28,27,23],[29,28,23],[30,29,23],[25,31,32],[22,33,34],[35,36,37],[24,38,39],[21,40,41],[38,42,20],[33,43,44],[6,4,23],[6,23,25],[36,35,1],[1,0,38],[1,38,36],[29,30,4],[25,32,6],[40,42,0],[35,45,1],[4,3,28],[4,28,29],[3,1,45],[3,45,28],[22,34,19],[19,6,32],[19,32,22],[42,38,0],[30,23,4],[0,16,43],[0,43,40],[24,37,36],[38,24,36],[24,23,37],[37,23,26],[22,32,20],[20,32,31],[33,41,40],[43,33,40],[45,35,26],[37,26,35],[33,44,34],[44,43,46],[20,42,21],[40,21,42],[31,39,38],[20,31,38],[33,22,41],[21,41,22],[31,25,39],[24,39,25],[26,27,45],[28,45,27],[47,48,49],[47,50,48],[51,48,50],[52,48,51],[53,48,52],[54,55,56],[57,55,54],[58,55,57],[49,59,47],[60,56,55],[59,56,60],[60,47,59],[48,53,16],[56,13,19],[54,56,19],[56,59,13],[59,49,14],[59,14,13],[49,48,16],[49,16,14],[44,46,60],[44,60,55],[51,50,43],[19,34,58],[19,58,57],[53,52,16],[43,16,52],[43,52,51],[57,54,19],[47,60,46],[55,58,34],[55,34,44],[50,47,46],[50,46,43]
+        ],
     }
     
     my $model = Slic3r::Model->new;
diff --git a/t/perimeters.t b/t/perimeters.t
new file mode 100644
index 000000000..9f3457cc2
--- /dev/null
+++ b/t/perimeters.t
@@ -0,0 +1,67 @@
+use Test::More tests => 2;
+use strict;
+use warnings;
+
+BEGIN {
+    use FindBin;
+    use lib "$FindBin::Bin/../lib";
+}
+
+use Slic3r;
+use Slic3r::Test;
+
+{
+    my $config = Slic3r::Config->new_from_defaults;
+    $config->set('skirts', 0);
+    $config->set('fill_density', 0);
+    $config->set('perimeters', 3);
+    $config->set('top_solid_layers', 0);
+    $config->set('bottom_solid_layers', 0);
+    $config->set('cooling', 0);                     # to prevent speeds to be altered
+    $config->set('first_layer_speed', '100%');      # to prevent speeds to be altered
+    
+    {
+        my $print = Slic3r::Test::init_print('overhang', config => $config);
+        my $has_cw_loops = 0;
+        my $cur_loop;
+        Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub {
+            my ($self, $cmd, $args, $info) = @_;
+            
+            if ($info->{extruding}) {
+                $cur_loop ||= [ [$self->X, $self->Y] ];
+                push @$cur_loop, [ @$info{qw(new_X new_Y)} ];
+            } else {
+                if ($cur_loop) {
+                    $has_cw_loops = 1 if !Slic3r::Geometry::Clipper::is_counter_clockwise($cur_loop);
+                    $cur_loop = undef;
+                }
+            }
+        });
+        ok !$has_cw_loops, 'all perimeters extruded ccw';
+    }
+    
+    {
+        $config->set('perimeters', 1);
+        $config->set('perimeter_speed', 77);
+        $config->set('external_perimeter_speed', 66);
+        $config->set('bridge_speed', 99);
+        my $print = Slic3r::Test::init_print('overhang', config => $config);
+        my %layer_speeds = ();  # print Z => [ speeds ]
+        Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub {
+            my ($self, $cmd, $args, $info) = @_;
+            
+            if ($info->{extruding} && $info->{dist_XY} > 0) {
+                $layer_speeds{$self->Z} ||= {};
+                $layer_speeds{$self->Z}{my $feedrate = $args->{F} // $self->F} = 1;
+                fail 'wrong speed found'
+                    if $feedrate != $config->perimeter_speed*60
+                        && $feedrate != $config->external_perimeter_speed*60
+                        && $feedrate != $config->bridge_speed*60;
+            }
+        });
+        is scalar(grep { keys %$_ > 1 } values %layer_speeds), 1,
+            'only overhang layer has more than one speed';
+    }
+}
+
+__END__