@Override
  public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) {
    if (child1 instanceof ReadOnlyBlock || child2 instanceof ReadOnlyBlock) {
      return Spacing.getReadOnlySpacing();
    }
    if (!(child1 instanceof AbstractXmlBlock) || !(child2 instanceof AbstractXmlBlock)) {
      return null;
    }
    ASTNode node1 = ((AbstractBlock)child1).getNode();
    ASTNode node2 = ((AbstractBlock)child2).getNode();

    IElementType type1 = node1.getElementType();
    IElementType type2 = node2.getElementType();

    if (type2 == XmlElementType.XML_COMMENT) {
      // Do not remove any spaces except extra blank lines
      return Spacing.createSpacing(0, Integer.MAX_VALUE, 0, true, myXmlFormattingPolicy.getKeepBlankLines());
    }
    if (type1 == XmlElementType.XML_COMMENT) {
      ASTNode prev = node1.getTreePrev();
      if (prev != null) {
        node1 = prev;
        type1 = prev.getElementType();
      }
    }

    boolean firstIsText = isTextFragment(node1);
    boolean secondIsText = isTextFragment(node2);

    if (((AbstractXmlBlock)child1).isPreserveSpace() && ((AbstractXmlBlock)child2).isPreserveSpace()) {
      ASTNode parent = node1.getTreeParent();
      boolean inText = parent != null && parent.getTreePrev().getElementType() == XmlTokenType.XML_TAG_END;
      if (inText) return Spacing.getReadOnlySpacing();
    }

    if (type1 == XmlTokenType.XML_CDATA_START || type2 == XmlTokenType.XML_CDATA_END) {
      if (myXmlFormattingPolicy.getKeepWhiteSpacesInsideCDATA()) {
        return Spacing.getReadOnlySpacing();
      }
      if (type1 == XmlTokenType.XML_CDATA_START && type2 == XmlTokenType.XML_CDATA_END) {
        return Spacing.createSpacing(0, 0, 0, myXmlFormattingPolicy.getShouldKeepLineBreaks(), myXmlFormattingPolicy.getKeepBlankLines());
      }
      if (type1 == XmlTokenType.XML_CDATA_START && child2 instanceof AnotherLanguageBlockWrapper ||
          type2 == XmlTokenType.XML_CDATA_END && child1 instanceof AnotherLanguageBlockWrapper) {
        return Spacing.createSpacing(0, 0, 1, myXmlFormattingPolicy.getShouldKeepLineBreaks(), 0);
      }
    }

    boolean firstIsTag = node1.getPsi() instanceof XmlTag && !firstIsText;
    boolean secondIsTag = node2.getPsi() instanceof XmlTag && !secondIsText;

    boolean firstIsEntityRef = isEntityRef(node1);
    boolean secondIsEntityRef = isEntityRef(node2);

    if ((secondIsText && isInlineTag(node1) || firstIsText && isInlineTag(node2)) &&
        myXmlFormattingPolicy.isKeepSpacesAroundInlineTags()) {
      return Spacing.getReadOnlySpacing();
    }

    if (isSpaceInText(firstIsTag, secondIsTag, firstIsText, secondIsText) && keepWhiteSpaces()) {
      return Spacing.getReadOnlySpacing();
    }

    if (firstIsEntityRef || secondIsEntityRef) {
      return Spacing.createSafeSpacing(myXmlFormattingPolicy.getShouldKeepLineBreaks(), myXmlFormattingPolicy.getKeepBlankLines());
    }

    if (isAttributeElementType(type1) && (type2 == XmlTokenType.XML_TAG_END || type2 == XmlTokenType.XML_EMPTY_ELEMENT_END)) {
      Spacing spacing = myXmlFormattingPolicy.getSpacingAfterLastAttribute((XmlAttribute)node1.getPsi());
      if (spacing != null) {
        return spacing;
      }
    }

    if (type2 == XmlTokenType.XML_EMPTY_ELEMENT_END && myXmlFormattingPolicy.addSpaceIntoEmptyTag()) {
      return Spacing.createSpacing(1, 1, 0,
                                   myXmlFormattingPolicy.getShouldKeepLineBreaks(),
                                   myXmlFormattingPolicy.getKeepBlankLines());
    }

    if (isXmlTagName(type1, type2)) {
      final int spaces = shouldAddSpaceAroundTagName(node1, node2) ? 1 : 0;
      return Spacing.createSpacing(spaces, spaces, 0, myXmlFormattingPolicy.getShouldKeepLineBreaks(),
                                   myXmlFormattingPolicy.getKeepBlankLines());
    }

    if (isAttributeElementType(type2)) {
      if (type1 == XmlTokenType.XML_NAME || type1 == XmlTokenType.XML_TAG_NAME) {
        Spacing spacing = myXmlFormattingPolicy.getSpacingBeforeFirstAttribute((XmlAttribute)node2.getPsi());
        if (spacing != null) {
          return spacing;
        }
      }
      return Spacing.createSpacing(1, 1, 0, myXmlFormattingPolicy.getShouldKeepLineBreaks(), myXmlFormattingPolicy.getKeepBlankLines());
    }

    if (type1 == XmlTokenType.XML_DATA_CHARACTERS && type2 == XmlTokenType.XML_DATA_CHARACTERS) {
      return Spacing.createSpacing(1, 1, 0,
                                   myXmlFormattingPolicy.getShouldKeepLineBreaksInText(), myXmlFormattingPolicy.getKeepBlankLines());
    }

    if (((AbstractXmlBlock)child1).isTextElement() && ((AbstractXmlBlock)child2).isTextElement()) {
      return Spacing.createSafeSpacing(myXmlFormattingPolicy.getShouldKeepLineBreaksInText(), myXmlFormattingPolicy.getKeepBlankLines());
    }

    if (firstIsTag && insertLineFeedAfter((XmlTag)node1.getPsi())) {
      return Spacing.createSpacing(0, 0, 1, true, myXmlFormattingPolicy.getKeepBlankLines());
    }

    if ((firstIsText || firstIsTag) && secondIsTag) {
      //<tag/>text <tag/></tag>
      if (((AbstractXmlBlock)child2).insertLineBreakBeforeTag()) {
        return Spacing.createSpacing(0, Integer.MAX_VALUE,
                                     ((AbstractXmlBlock)child2).getBlankLinesBeforeTag() + 1,
                                     myXmlFormattingPolicy.getShouldKeepLineBreaks(),
                                     myXmlFormattingPolicy.getKeepBlankLines());
      }
      else if (((AbstractXmlBlock)child2).removeLineBreakBeforeTag()) {
        return Spacing.createSpacing(0, Integer.MAX_VALUE, 0, myXmlFormattingPolicy.getShouldKeepLineBreaks(),
                                     myXmlFormattingPolicy.getKeepBlankLines());
      }
    }

    final boolean saveSpacesBetweenTagAndText =
      myXmlFormattingPolicy.shouldSaveSpacesBetweenTagAndText() &&
      child1.getTextRange().getEndOffset() < child2.getTextRange().getStartOffset();

    if (firstIsTag && secondIsText) {     //<tag/>-text

      if (((AbstractXmlBlock)child1).isTextElement() || saveSpacesBetweenTagAndText) {
        return Spacing.createSafeSpacing(true, myXmlFormattingPolicy.getKeepBlankLines());
      }
      else {
        return Spacing.createSpacing(0, 0, 0, true, myXmlFormattingPolicy.getKeepBlankLines());
      }
    }

    if (firstIsText && secondIsTag) {     //text-<tag/>
      if (((AbstractXmlBlock)child2).isTextElement() || saveSpacesBetweenTagAndText) {
        return Spacing.createSafeSpacing(true, myXmlFormattingPolicy.getKeepBlankLines());
      }
      else {
        return Spacing.createSpacing(0, 0, 0, true, myXmlFormattingPolicy.getKeepBlankLines());
      }
    }

    if (firstIsTag && secondIsTag) {//<tag/><tag/>
      return Spacing.createSpacing(0, Integer.MAX_VALUE, 0, true,
                                   myXmlFormattingPolicy.getKeepBlankLines());
    }

    return Spacing.createSpacing(0, Integer.MAX_VALUE, 0, myXmlFormattingPolicy.getShouldKeepLineBreaksInText(),
                                 myXmlFormattingPolicy.getKeepBlankLines());
  }
@Override
  public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2)