Index: /trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java	(revision 9824)
+++ /trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java	(revision 9825)
@@ -47,5 +47,4 @@
 import org.openstreetmap.josm.data.projection.Projections;
 import org.openstreetmap.josm.gui.ExtendedDialog;
-import org.openstreetmap.josm.gui.layer.NativeScaleLayer.Scale;
 import org.openstreetmap.josm.gui.layer.NativeScaleLayer.ScaleList;
 import org.openstreetmap.josm.io.CachedFile;
@@ -246,4 +245,6 @@
     private TransferMode transferMode;
 
+    private ScaleList nativeScaleList;
+
     /**
      * Creates a tile source based on imagery info
@@ -631,4 +632,12 @@
 
         this.crsScale = getTileSize() * 0.28e-03 / proj.getMetersPerUnit();
+
+        Collection<Double> scales = new ArrayList<>(currentTileMatrixSet.tileMatrix.size());
+        if (currentTileMatrixSet != null) {
+            for (TileMatrix tileMatrix : currentTileMatrixSet.tileMatrix) {
+                scales.add(tileMatrix.scaleDenominator * 0.28e-03);
+            }
+        }
+        this.nativeScaleList = new ScaleList(scales);
     }
 
@@ -919,11 +928,5 @@
      */
     public ScaleList getNativeScales() {
-        ScaleList scales = new ScaleList();
-        if (currentTileMatrixSet != null) {
-            for (TileMatrix tileMatrix : currentTileMatrixSet.tileMatrix) {
-                scales.add(new Scale(tileMatrix.scaleDenominator * 0.28e-03));
-            }
-        }
-        return scales;
+        return nativeScaleList;
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 9824)
+++ /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 9825)
@@ -156,5 +156,4 @@
     public NavigatableComponent() {
         setLayout(null);
-        PROP_ZOOM_RATIO.get(); // make sure it is available in preferences
     }
 
@@ -208,5 +207,5 @@
             }
             Scale scale = scaleList.scaleZoomTimes(getScale(), PROP_ZOOM_RATIO.get(), times);
-            return scale.scale;
+            return scale.getScale();
         } else {
             return getScale() * Math.pow(PROP_ZOOM_RATIO.get(), times);
@@ -245,5 +244,5 @@
         if (nativeScaleLayer != null) {
             ScaleList scaleList = nativeScaleLayer.getNativeScales();
-            return scaleList.getSnapScale(scale, PROP_ZOOM_RATIO.get(), floor).scale;
+            return scaleList.getSnapScale(scale, PROP_ZOOM_RATIO.get(), floor).getScale();
         } else {
             return scale;
Index: /trunk/src/org/openstreetmap/josm/gui/layer/NativeScaleLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/NativeScaleLayer.java	(revision 9824)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/NativeScaleLayer.java	(revision 9825)
@@ -3,4 +3,6 @@
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 
 import org.openstreetmap.josm.gui.NavigatableComponent;
@@ -25,10 +27,10 @@
          * Scale factor, same unit as in {@link NavigatableComponent}
          */
-        public double scale;
+        private double scale;
 
         /**
          * True if this scale is native resolution for data source.
          */
-        public boolean isNative;
+        private boolean isNative;
 
         private int index;
@@ -37,18 +39,10 @@
          * Constructs a new Scale with given scale, native defaults to true.
          * @param scale as defined in WMTS (scaleDenominator)
-         */
-        public Scale(double scale) {
+         * @param index zoom index for this scale
+         */
+        public Scale(double scale, int index) {
             this.scale = scale;
             this.isNative = true;
-        }
-
-        /**
-         * Constructs a new Scale with given scale and native values.
-         * @param scale as defined in WMTS (scaleDenominator)
-         * @param isNative is this scale native to the source or not
-         */
-        public Scale(double scale, boolean isNative) {
-            this.scale = scale;
-            this.isNative = isNative;
+            this.index = index;
         }
 
@@ -77,4 +71,8 @@
             return index;
         }
+
+        public double getScale() {
+            return scale;
+        }
     }
 
@@ -83,5 +81,26 @@
      * between native resolutions
      */
-    class ScaleList extends ArrayList<Scale> {
+    class ScaleList  {
+        private List<Scale> scales = new ArrayList<>();
+
+        protected ScaleList(double[] scales) {
+            for (int i = 0; i < scales.length; i++) {
+                this.scales.add(new Scale(scales[i], i));
+            }
+        }
+
+        protected ScaleList() {
+        }
+
+        public ScaleList(Collection<Double> scales) {
+            int i = 0;
+            for (Double scale: scales) {
+                this.scales.add(new Scale(scale, i++));
+            }
+        }
+
+        protected void addScale(Scale scale) {
+            scales.add(scale);
+        }
 
         /**
@@ -94,5 +113,5 @@
             ScaleList result = new ScaleList();
             Scale previous = null;
-            for (Scale current: this) {
+            for (Scale current: this.scales) {
                 if (previous != null) {
                     double step = previous.scale / current.scale;
@@ -102,11 +121,21 @@
                     for (int j = 1; j < steps; j++) {
                         double intermediate = previous.scale / Math.pow(smallStep, j);
-                        result.add(new Scale(intermediate, false));
+                        result.addScale(new Scale(intermediate, false, current.index));
                     }
                 }
-                result.add(current);
+                result.addScale(current);
                 previous = current;
             }
             return result;
+        }
+
+        /**
+         * Get a scale from this ScaleList or a new scale if zoomed outside.
+         * @param scale previous scale
+         * @param floor use floor instead of round, set true when fitting view to objects
+         * @return new {@link Scale}
+         */
+        public Scale getSnapScale(double scale, boolean floor) {
+            return getSnapScale(scale, NavigatableComponent.PROP_ZOOM_RATIO.get(), floor);
         }
 
@@ -119,7 +148,8 @@
          */
         public Scale getSnapScale(double scale, double ratio, boolean floor) {
-            int size = size();
-            Scale first = get(0);
-            Scale last = get(size-1);
+            int size = scales.size();
+            Scale first = scales.get(0);
+            Scale last = scales.get(size-1);
+
             if (scale > first.scale) {
                 double step = scale / first.scale;
@@ -143,5 +173,5 @@
                 Scale previous = null;
                 for (int i = 0; i < size; i++) {
-                    Scale current = this.get(i);
+                    Scale current = this.scales.get(i);
                     if (previous != null) {
                         if (scale <= previous.scale && scale >= current.scale) {
@@ -207,5 +237,5 @@
         public String toString() {
             StringBuilder stringBuilder = new StringBuilder();
-            for (Scale s: this) {
+            for (Scale s: this.scales) {
                 stringBuilder.append(s + "\n");
             }
@@ -215,8 +245,8 @@
         private Scale getNextIn(Scale scale, double ratio) {
             int nextIndex = scale.getIndex() + 1;
-            if (nextIndex <= 0 || nextIndex > size()-1) {
+            if (nextIndex <= 0 || nextIndex > this.scales.size()-1) {
                 return new Scale(scale.scale / ratio, nextIndex == 0, nextIndex);
             } else {
-                Scale nextScale = get(nextIndex);
+                Scale nextScale = this.scales.get(nextIndex);
                 return new Scale(nextScale.scale, nextScale.isNative, nextIndex);
             }
@@ -225,8 +255,8 @@
         private Scale getNextOut(Scale scale, double ratio) {
             int nextIndex = scale.getIndex() - 1;
-            if (nextIndex < 0 || nextIndex >= size()-1) {
-                return new Scale(scale.scale * ratio, nextIndex == size()-1, nextIndex);
+            if (nextIndex < 0 || nextIndex >= this.scales.size()-1) {
+                return new Scale(scale.scale * ratio, nextIndex == this.scales.size()-1, nextIndex);
             } else {
-                Scale nextScale = get(nextIndex);
+                Scale nextScale = this.scales.get(nextIndex);
                 return new Scale(nextScale.scale, nextScale.isNative, nextIndex);
             }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/TMSLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/TMSLayer.java	(revision 9824)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/TMSLayer.java	(revision 9825)
@@ -3,4 +3,7 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.Collection;
 
 import org.apache.commons.jcs.access.CacheAccess;
@@ -45,4 +48,6 @@
             true);
 
+    private ScaleList nativeScaleList;
+
     /**
      * Create a layer based on ImageryInfo
@@ -51,4 +56,10 @@
     public TMSLayer(ImageryInfo info) {
         super(info);
+        Collection<Double> scales = new ArrayList<>(info.getMaxZoom());
+        for (int zoom = info.getMinZoom(); zoom <= info.getMaxZoom(); zoom++) {
+            double scale = OsmMercator.EARTH_RADIUS * Math.PI * 2 / Math.pow(2, zoom) / OsmMercator.DEFAUL_TILE_SIZE;
+            scales.add(scale);
+        }
+        this.nativeScaleList = new ScaleList(scales);
     }
 
@@ -149,10 +160,5 @@
     @Override
     public ScaleList getNativeScales() {
-        ScaleList scales = new ScaleList();
-        for (int zoom = info.getMinZoom(); zoom <= info.getMaxZoom(); zoom++) {
-            double scale = OsmMercator.EARTH_RADIUS * Math.PI * 2 / Math.pow(2, zoom) / OsmMercator.DEFAUL_TILE_SIZE;
-            scales.add(new Scale(scale));
-        }
-        return scales;
+        return nativeScaleList;
     }
-}
+ }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java	(revision 9824)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java	(revision 9825)
@@ -62,17 +62,11 @@
     protected int getBestZoom() {
         if (!Main.isDisplayingMapView()) return 0;
-        ScaleList scaleList = getNativeScales();
-        for (int i = scaleList.size()-1; i >= 0; i--) {
-            Scale scale = scaleList.get(i);
-            if (scale.scale >= Main.map.mapView.getScale()) {
-                return i;
-            }
-        }
-        return 0;
-    }
-
-    @Override
-    protected int getMaxZoomLvl() {
-        return getNativeScales().size()-1;
+        return Math.max(
+                getMinZoomLvl(),
+                Math.min(
+                        getNativeScales().getSnapScale(Main.map.mapView.getScale(), false).getIndex(),
+                        getMaxZoomLvl()
+                        )
+                );
     }
 
