title: Binding Shape and Size of Node to Clipping Mask in JavaFX
body: <p>Is there a convenient way for a clipping mask to just bind whatever shape/size the target node has? Consider the following Region node:</p>
  
  <pre><code>import javafx.application.Application;
  import javafx.scene.layout.Region;
  import javafx.scene.layout.StackPane;
  import javafx.scene.Scene;
  import javafx.stage.Stage;
  
  public class App extends Application {
  
      @Override
      public void start(Stage stage) throws Exception {
          Region content = new Region();
          content.setStyle(
              "-fx-background-color: #444444;" +
              "-fx-background-radius: 50px;" +
              "-fx-max-width: 150px;" +
              "-fx-max-height: 150px;");
          StackPane root = new StackPane(content);
          Scene scene = new Scene(root, 300, 300);
          stage.setScene(scene);
          stage.show();
      }
  }
  </code></pre>
  
  <p>How can I have a mask that can automatically adjust its own shape and size accordingly?</p>
  
  <hr>
  
  <h3>EDIT</h3>
  
  <p>This is how I implement this stuff, but it's too long and inconvenient:</p>
  
  <pre><code>import javafx.application.Application;
  import javafx.scene.layout.BackgroundFill;
  import javafx.scene.layout.Region;
  import javafx.scene.Scene;
  import javafx.scene.shape.Rectangle;
  import javafx.stage.Stage;
  
  public class App extends Application {
  
      @Override
      public void start(Stage stage) throws Exception {
          Region content1 = new Region();
          content1.setStyle(
              "-fx-background-color: teal;" +
              "-fx-background-radius: 50px;" +
              "-fx-pref-width: 150px;" +
              "-fx-pref-height: 150px;" +
              "-fx-translate-x: 30px;" +
              "-fx-translate-y: 30px;");
  
          Rectangle mask = new Rectangle();
  
          Region content2 = new Region() {{
              // TODO: Implement better clip mask size and shape handling
              mask.widthProperty().bind(widthProperty());
              mask.heightProperty().bind(heightProperty());
              backgroundProperty().addListener(((observable, oldBackground, newBackground) -&gt; {
                  for (BackgroundFill backgroundFill : newBackground.getFills()) {
                      double topLeftHRadius = backgroundFill.getRadii().getTopLeftHorizontalRadius();
                      double topLeftVRadius = backgroundFill.getRadii().getTopLeftVerticalRadius();
                      double topRightHRadius = backgroundFill.getRadii().getTopRightHorizontalRadius();
                      double topRightVRadius = backgroundFill.getRadii().getTopRightVerticalRadius();
                      double bottomLeftHRadius = backgroundFill.getRadii().getBottomLeftHorizontalRadius();
                      double bottomLeftVRadius = backgroundFill.getRadii().getBottomLeftVerticalRadius();
                      double bottomRightHRadius = backgroundFill.getRadii().getBottomRightHorizontalRadius();
                      double bottomRightVRadius = backgroundFill.getRadii().getBottomRightVerticalRadius();
                      mask.setArcWidth((topLeftHRadius + topRightHRadius + bottomLeftHRadius + bottomRightHRadius) / 2);
                      mask.setArcHeight((topLeftVRadius + topRightVRadius + bottomLeftVRadius + bottomRightVRadius) / 2);
                  }
              }));
              setClip(mask);
              getChildren().add(content1);
          }};
          content2.setStyle(
              "-fx-background-color: cyan;" +
              "-fx-background-radius: 50px;" +
              "-fx-pref-width: 150px;" +
              "-fx-pref-height: 150px;" +
              "-fx-translate-x: 70px;" +
              "-fx-translate-y: 70px;");
  
          Region root = new Region() {{
              getChildren().add(content2);
          }};
  
          Scene scene = new Scene(root, 300, 300);
  
          stage.setScene(scene);
          stage.setResizable(false);
          stage.show();
      }
  }
  </code></pre>
  
  <p>I'm looking for a convenient, and better way to do this. On the other hand, the HTML + CSS <a href="https://www.w3schools.com/css/css_overflow.asp" rel="nofollow noreferrer">overflow</a> property can easily achieve this:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-css lang-css prettyprint-override"><code>div {
    position: relative;
    background-color: cyan;
    border-radius: 50px;
    width: 150px;
    height: 150px;
    /* clipping property */
    overflow: hidden;
  }
  
  div:before {
    content: '';
    position: absolute;
    top: 30px;
    left: 30px;
    background-color: teal;
    border-radius: inherit;
    width: 100%;
    height: 100%;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;div&gt;&lt;/div&gt;</code></pre>
  </div>
  </div>
  </p>