Index: Readme.txt
===================================================================
--- Readme.txt	(revision 36386)
+++ Readme.txt	(working copy)
@@ -35,11 +35,11 @@
 
 2. How does JMapViewer work?
 
-JMapViewer loads bitmap tiles from the OpenStreetmap tile server (Mapnik renderer).
-Therefore any application using JMapViewer requires a working Internet connection.    
+JMapViewer loads bitmap tiles from the OpenStreetMap tile server (Mapnik renderer).
+Therefore, any application using JMapViewer requires a working Internet connection.
 
 3. How do I use JMapViewer in my application?
 
-You can just create an instance of the class org.openstreetmap.gui.jmapviewer.JMapViewer
+You can create an instance of the class org.openstreetmap.gui.jmapviewer.JMapViewer
 using the default constructor and add it to your panel/frame/windows.
-For more details please see the Demo class in the same package.
+For more details, please see the Demo class in the same package.
Index: src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java
===================================================================
--- src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java	(revision 36386)
+++ src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java	(working copy)
@@ -62,59 +62,53 @@
             return;
         }
 
-        // Draw attribution
         Font font = g.getFont();
         g.setFont(ATTR_LINK_FONT);
 
-        // Draw terms of use text
+        // Draw terms of use text (bottom left corner)
+        final int padding = 4;  // should be positive
+        final int fontDescent = g.getFontMetrics().getDescent();
         int termsTextHeight = 0;
-        int termsTextY = height;
+        int termsTextY = height - 1 - padding;  // the 1 is to compensate the text shadow
 
         if (attrTermsText != null) {
             Rectangle2D termsStringBounds = g.getFontMetrics().getStringBounds(attrTermsText, g);
             int textRealHeight = (int) termsStringBounds.getHeight();
-            termsTextHeight = textRealHeight - 5;
             int termsTextWidth = (int) termsStringBounds.getWidth();
-            termsTextY = height - termsTextHeight;
-            int x = 2;
-            int y = height - termsTextHeight;
-            attrToUBounds = new Rectangle(x, y-termsTextHeight, termsTextWidth, textRealHeight);
-            g.setColor(Color.black);
-            g.drawString(attrTermsText, x + 1, y + 1);
-            g.setColor(Color.white);
-            g.drawString(attrTermsText, x, y);
+            termsTextHeight = textRealHeight;
+            attrToUBounds = new Rectangle(padding, termsTextY - termsTextHeight + fontDescent, termsTextWidth, textRealHeight);
+            drawShadedText(g, attrTermsText, padding, termsTextY);
+            drawRectangleWithBorder(g, attrToUBounds);
         } else {
             attrToUBounds = null;
         }
 
-        // Draw attribution logo
+        // Draw attribution logo (on top the terms of use text)
         if (attrImage != null) {
-            int x = 2;
             int imgWidth = attrImage.getWidth(observer);
             int imgHeight = attrImage.getHeight(observer);
-            int y = termsTextY - imgHeight - termsTextHeight - 5;
-            attrImageBounds = new Rectangle(x, y, imgWidth, imgHeight);
-            g.drawImage(attrImage, x, y, null);
+            int y = termsTextY - imgHeight - termsTextHeight;
+            attrImageBounds = new Rectangle(padding, y, imgWidth, imgHeight);
+            g.drawImage(attrImage, padding, y, null);
         } else {
             attrImageBounds = null;
         }
 
+        // Draw attribution (bottom right corner)
         g.setFont(ATTR_FONT);
         String attributionText = source.getAttributionText(zoom, topLeft, bottomRight);
         if (attributionText == null) {
-            // In case attribution text has been forgotte, display URL
+            // In case the attribution text has been forgotten, display URL
             attributionText = source.getAttributionLinkURL();
         }
         if (attributionText != null) {
             Rectangle2D stringBounds = g.getFontMetrics().getStringBounds(attributionText, g);
-            int textHeight = (int) stringBounds.getHeight() - 5;
-            int x = width - (int) stringBounds.getWidth();
-            int y = height - textHeight;
-            g.setColor(Color.black);
-            g.drawString(attributionText, x + 1, y + 1);
-            g.setColor(Color.white);
-            g.drawString(attributionText, x, y);
-            attrTextBounds = new Rectangle(x, y-textHeight, (int) stringBounds.getWidth(), (int) stringBounds.getHeight());
+            int textWidth = (int) stringBounds.getWidth();
+            int textHeight = (int) stringBounds.getHeight();
+            int x = width - textWidth - padding;
+            drawShadedText(g, attributionText, x, termsTextY);
+            attrTextBounds = new Rectangle(x, termsTextY - textHeight + fontDescent, textWidth, textHeight);
+            drawRectangleWithBorder(g, attrTextBounds);
         } else {
             attrTextBounds = null;
         }
@@ -122,6 +116,28 @@
         g.setFont(font);
     }
 
+    /**
+     * Used for debugging. Draws a red outline of the given rectangle.
+     */
+    private void drawRectangleWithBorder(Graphics g, Rectangle rect) {
+        g.setColor(Color.RED);
+        g.drawRect(rect.x, rect.y, rect.width, rect.height);
+    }
+
+    /**
+     * Draws a string with 1px shadow.
+     * @param g the graphics
+     * @param text the string to be drawn
+     * @param x the x coordinate
+     * @param y the y coordinate
+     */
+    private static void drawShadedText(Graphics g, String text, int x, int y) {
+        g.setColor(Color.black);
+        g.drawString(text, x + 1, y + 1);
+        g.setColor(Color.white);
+        g.drawString(text, x, y);
+    }
+
     public boolean handleAttributionCursor(Point p) {
         if (attrTextBounds != null && attrTextBounds.contains(p)) {
             return true;
@@ -166,4 +182,3 @@
     }
 
 }
-
Index: src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java
===================================================================
--- src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java	(revision 36386)
+++ src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java	(working copy)
@@ -180,7 +180,7 @@
      * @param url URL to check
      */
     public static void checkUrl(String url) {
-        assert url != null && !"".equals(url) : "URL cannot be null or empty";
+        assert url != null && !url.isEmpty() : "URL cannot be null or empty";
         Matcher m = Pattern.compile("\\{[^}]*}").matcher(url);
         while (m.find()) {
             boolean isSupportedPattern = Arrays.stream(ALL_PATTERNS).anyMatch(pattern -> pattern.matcher(m.group()).matches());
