]> git.lyx.org Git - features.git/blobdiff - src/insets/InsetSpace.cpp
Regenerate previews after zoom (#11919)
[features.git] / src / insets / InsetSpace.cpp
index 839ccc917b194e64b7f9912bb22c418744772d0d..3f86eb8c074cf1c1775b6ca50c920d72e3fa85fc 100644 (file)
 #include "FuncStatus.h"
 #include "Language.h"
 #include "LaTeXFeatures.h"
-#include "Length.h"
 #include "Lexer.h"
 #include "MetricsInfo.h"
-#include "OutputParams.h"
-#include "output_xhtml.h"
+#include "texstream.h"
+#include "xml.h"
 
 #include "support/debug.h"
 #include "support/docstream.h"
 #include "support/gettext.h"
 #include "support/lassert.h"
+#include "support/Length.h"
 #include "support/lstrings.h"
+#include "support/qstring_helpers.h"
 
 #include "frontends/Application.h"
 #include "frontends/FontMetrics.h"
@@ -44,7 +45,7 @@ namespace lyx {
 
 
 InsetSpace::InsetSpace(InsetSpaceParams const & params)
-       : Inset(0), params_(params)
+       : Inset(nullptr), params_(params)
 {}
 
 
@@ -65,77 +66,77 @@ docstring InsetSpace::toolTip(BufferView const &, int, int) const
        docstring message;
        switch (params_.kind) {
        case InsetSpaceParams::NORMAL:
-               message = _("Interword Space");
+               message = _("Normal Space");
                break;
        case InsetSpaceParams::PROTECTED:
-               message = _("Protected Space");
+               message = _("Non-Breaking Normal Space");
                break;
        case InsetSpaceParams::VISIBLE:
-               message = _("Visible Space");
+               message = _("Non-Breaking Visible Normal Space");
                break;
        case InsetSpaceParams::THIN:
-               message = _("Thin Space");
+               message = _("Non-Breaking Thin Space (1/6 em)");
                break;
        case InsetSpaceParams::MEDIUM:
-               message = _("Medium Space");
+               message = _("Non-Breaking Medium Space (2/9 em)");
                break;
        case InsetSpaceParams::THICK:
-               message = _("Thick Space");
+               message = _("Non-Breaking Thick Space (5/18 em)");
                break;
        case InsetSpaceParams::QUAD:
-               message = _("Quad Space");
+               message = _("Quad Space (1 em)");
                break;
        case InsetSpaceParams::QQUAD:
-               message = _("Double Quad Space");
+               message = _("Double Quad Space (2 em)");
                break;
        case InsetSpaceParams::ENSPACE:
-               message = _("Enspace");
+               message = _("Non-Breaking Half Quad Space (1/2 em)");
                break;
        case InsetSpaceParams::ENSKIP:
-               message = _("Enskip");
+               message = _("Half Quad Space (1/2 em)");
                break;
        case InsetSpaceParams::NEGTHIN:
-               message = _("Negative Thin Space");
+               message = _("Non-Breaking Negative Thin Space (-1/6 em)");
                break;
        case InsetSpaceParams::NEGMEDIUM:
-               message = _("Negative Medium Space");
+               message = _("Non-Breaking Negative Medium Space (-2/9 em)");
                break;
        case InsetSpaceParams::NEGTHICK:
-               message = _("Negative Thick Space");
+               message = _("Non-Breaking Negative Thick Space (-5/18 em)");
                break;
        case InsetSpaceParams::HFILL:
                message = _("Horizontal Fill");
                break;
        case InsetSpaceParams::HFILL_PROTECTED:
-               message = _("Protected Horizontal Fill");
+               message = _("Non-Breaking Horizontal Fill");
                break;
        case InsetSpaceParams::DOTFILL:
-               message = _("Horizontal Fill (Dots)");
+               message = _("Non-Breaking Horizontal Fill (Dots)");
                break;
        case InsetSpaceParams::HRULEFILL:
-               message = _("Horizontal Fill (Rule)");
+               message = _("Non-Breaking Horizontal Fill (Rule)");
                break;
        case InsetSpaceParams::LEFTARROWFILL:
-               message = _("Horizontal Fill (Left Arrow)");
+               message = _("Non-Breaking Horizontal Fill (Left Arrow)");
                break;
        case InsetSpaceParams::RIGHTARROWFILL:
-               message = _("Horizontal Fill (Right Arrow)");
+               message = _("Non-Breaking Horizontal Fill (Right Arrow)");
                break;
        case InsetSpaceParams::UPBRACEFILL:
-               message = _("Horizontal Fill (Up Brace)");
+               message = _("Non-Breaking Horizontal Fill (Up Brace)");
                break;
        case InsetSpaceParams::DOWNBRACEFILL:
-               message = _("Horizontal Fill (Down Brace)");
+               message = _("Non-Breaking Horizontal Fill (Down Brace)");
                break;
        case InsetSpaceParams::CUSTOM:
                // FIXME unicode
                message = support::bformat(_("Horizontal Space (%1$s)"),
-                               from_ascii(params_.length.asString()));
+                                          locLengthDocString(from_ascii(params_.length.asString())));
                break;
        case InsetSpaceParams::CUSTOM_PROTECTED:
                // FIXME unicode
-               message = support::bformat(_("Protected Horizontal Space (%1$s)"),
-                               from_ascii(params_.length.asString()));
+               message = support::bformat(_("Non-Breaking Horizontal Space (%1$s)"),
+                                          locLengthDocString(from_ascii(params_.length.asString())));
                break;
        }
        return message;
@@ -192,6 +193,41 @@ bool InsetSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
 }
 
 
+int InsetSpace::rowFlags() const
+{
+       switch (params_.kind) {
+               case InsetSpaceParams::PROTECTED:
+               case InsetSpaceParams::CUSTOM_PROTECTED:
+               case InsetSpaceParams::HFILL_PROTECTED:
+               case InsetSpaceParams::THIN:
+               case InsetSpaceParams::NEGTHIN:
+               case InsetSpaceParams::MEDIUM:
+               case InsetSpaceParams::NEGMEDIUM:
+               case InsetSpaceParams::THICK:
+               case InsetSpaceParams::NEGTHICK:
+               case InsetSpaceParams::ENSPACE:
+               case InsetSpaceParams::VISIBLE:
+                       // no break after these
+                       return Inline;
+               case InsetSpaceParams::NORMAL:
+               case InsetSpaceParams::QUAD:
+               case InsetSpaceParams::QQUAD:
+               case InsetSpaceParams::ENSKIP:
+               case InsetSpaceParams::CUSTOM:
+               case InsetSpaceParams::HFILL:
+               case InsetSpaceParams::DOTFILL:
+               case InsetSpaceParams::HRULEFILL:
+               case InsetSpaceParams::LEFTARROWFILL:
+               case InsetSpaceParams::RIGHTARROWFILL:
+               case InsetSpaceParams::UPBRACEFILL:
+               case InsetSpaceParams::DOWNBRACEFILL:
+                       // these allow line breaking
+                       break;
+       }
+       return CanBreakAfter;
+}
+
+
 namespace {
 int const arrow_size = 8;
 }
@@ -200,9 +236,10 @@ int const arrow_size = 8;
 void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
 {
        if (isHfill()) {
-               // The metrics for this kinds are calculated externally in
-               // \c TextMetrics::computeRowMetrics. Those are dummy value:
-               dim = Dimension(10, 10, 10);
+               // The width for hfills is calculated externally in
+               // TextMetrics::setRowAlignment. The value of 5 is the
+               // minimal value when the hfill is not active.
+               dim = Dimension(5, 10, 10);
                return;
        }
 
@@ -241,8 +278,7 @@ void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
                        break;
                case InsetSpaceParams::CUSTOM:
                case InsetSpaceParams::CUSTOM_PROTECTED: {
-                       int const w =
-                               params_.length.len().inPixels(mi.base);
+                       int const w = mi.base.inPixels(params_.length.len());
                        int const minw = (w < 0) ? 3 * arrow_size : 4;
                        dim.wid = max(minw, abs(w));
                        break;
@@ -258,8 +294,6 @@ void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
                        // shut up compiler
                        break;
        }
-       // Cache the inset dimension.
-       setDimCache(mi, dim);
 }
 
 
@@ -353,7 +387,7 @@ void InsetSpace::draw(PainterInfo & pi, int x, int y) const
        }
 
        int const w = dim.wid;
-       int const h = theFontMetrics(pi.base.font).ascent('x');
+       int const h = theFontMetrics(pi.base.font).xHeight();
        int xp[4], yp[4];
 
        xp[0] = x;
@@ -361,20 +395,23 @@ void InsetSpace::draw(PainterInfo & pi, int x, int y) const
        if (params_.kind == InsetSpaceParams::NORMAL ||
            params_.kind == InsetSpaceParams::PROTECTED ||
            params_.kind == InsetSpaceParams::VISIBLE) {
-               xp[1] = x;     yp[1] = y;
-               xp[2] = x + w; yp[2] = y;
+               xp[1] = x;         yp[1] = y;
+               xp[2] = x + w - 1; yp[2] = y;
        } else {
-               xp[1] = x;     yp[1] = y + max(h / 4, 1);
-               xp[2] = x + w; yp[2] = y + max(h / 4, 1);
+               xp[1] = x;         yp[1] = y + max(h / 4, 1);
+               xp[2] = x + w - 1; yp[2] = y + max(h / 4, 1);
        }
-       xp[3] = x + w;
+       xp[3] = x + w - 1;
        yp[3] = y - max(h / 4, 1);
 
        Color col = Color_special;
        if (params_.kind == InsetSpaceParams::PROTECTED ||
            params_.kind == InsetSpaceParams::ENSPACE ||
+           params_.kind == InsetSpaceParams::THIN ||
            params_.kind == InsetSpaceParams::NEGTHIN ||
+           params_.kind == InsetSpaceParams::MEDIUM ||
            params_.kind == InsetSpaceParams::NEGMEDIUM ||
+           params_.kind == InsetSpaceParams::THICK ||
            params_.kind == InsetSpaceParams::NEGTHICK ||
            params_.kind == InsetSpaceParams::CUSTOM_PROTECTED)
                col = Color_latex;
@@ -387,7 +424,6 @@ void InsetSpace::draw(PainterInfo & pi, int x, int y) const
 
 void InsetSpaceParams::write(ostream & os) const
 {
-       string command;
        switch (kind) {
        case InsetSpaceParams::NORMAL:
                os << "\\space{}";
@@ -480,9 +516,9 @@ void InsetSpaceParams::read(Lexer & lex)
                kind = InsetSpaceParams::VISIBLE;
        else if (command == "\\thinspace{}")
                kind = InsetSpaceParams::THIN;
-       else if (math && command == "\\medspace{}")
+       else if (command == "\\medspace{}")
                kind = InsetSpaceParams::MEDIUM;
-       else if (math && command == "\\thickspace{}")
+       else if (command == "\\thickspace{}")
                kind = InsetSpaceParams::THICK;
        else if (command == "\\quad{}")
                kind = InsetSpaceParams::QUAD;
@@ -544,10 +580,15 @@ void InsetSpace::latex(otexstream & os, OutputParams const & runparams) const
 {
        switch (params_.kind) {
        case InsetSpaceParams::NORMAL:
-               os << (runparams.free_spacing ? " " : "\\ ");
+               if (runparams.find_effective())
+                       os << "~";
+               else
+                       os << (runparams.free_spacing ? " " : "\\ ");
                break;
        case InsetSpaceParams::PROTECTED:
-               if (runparams.local_font &&
+               if (runparams.find_effective())
+                       os.put(0xa0);
+               else if (runparams.local_font &&
                    runparams.local_font->language()->lang() == "polutonikogreek")
                        // in babel's polutonikogreek, ~ is active
                        os << (runparams.free_spacing ? " " : "\\nobreakspace{}");
@@ -555,70 +596,104 @@ void InsetSpace::latex(otexstream & os, OutputParams const & runparams) const
                        os << (runparams.free_spacing ? ' ' : '~');
                break;
        case InsetSpaceParams::VISIBLE:
-               os << (runparams.free_spacing ? " " : "\\textvisiblespace{}");
+               if (runparams.find_effective())
+                       os.put(0x2423);
+               else
+                       os << (runparams.free_spacing ? " " : "\\textvisiblespace{}");
                break;
        case InsetSpaceParams::THIN:
-               os << (runparams.free_spacing ? " " : "\\,");
+               if (runparams.find_effective())
+                       os.put(0x2009);
+               else
+                       os << (runparams.free_spacing ? " " : "\\,");
                break;
        case InsetSpaceParams::MEDIUM:
-               os << (runparams.free_spacing ? " " : "\\:");
+               if (runparams.find_effective())
+                       os.put(0x2005);
+               else if (params_.math)
+                       os << (runparams.free_spacing ? " " : "\\:");
+               else
+                       os << (runparams.free_spacing ? " " : "\\medspace{}");
                break;
        case InsetSpaceParams::THICK:
-               os << (runparams.free_spacing ? " " : "\\;");
+               if (runparams.find_effective())
+                       os.put(0x2004);
+               else if (params_.math)
+                       os << (runparams.free_spacing ? " " : "\\;");
+               else
+                       os << (runparams.free_spacing ? " " : "\\thickspace{}");
                break;
        case InsetSpaceParams::QUAD:
-               os << (runparams.free_spacing ? " " : "\\quad{}");
+               if (runparams.find_effective())
+                       os.put(0x2003);
+               else
+                       os << (runparams.free_spacing ? " " : "\\quad{}");
                break;
        case InsetSpaceParams::QQUAD:
-               os << (runparams.free_spacing ? " " : "\\qquad{}");
+               if (runparams.find_effective()) {
+                       os.put(0x2003);
+                       os.put(0x2003);
+               }
+               else
+                       os << (runparams.free_spacing ? " " : "\\qquad{}");
                break;
        case InsetSpaceParams::ENSPACE:
-               os << (runparams.free_spacing ? " " : "\\enspace{}");
+               if (runparams.find_effective())
+                       os.put(0x2002);
+               else
+                       os << (runparams.free_spacing ? " " : "\\enspace{}");
                break;
        case InsetSpaceParams::ENSKIP:
-               os << (runparams.free_spacing ? " " : "\\enskip{}");
+               if (runparams.find_effective())
+                       os.put(0x2002);
+               else
+                       os << (runparams.free_spacing ? " " : "\\enskip{}");
                break;
        case InsetSpaceParams::NEGTHIN:
-               os << (runparams.free_spacing ? " " : "\\negthinspace{}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\negthinspace{}");
                break;
        case InsetSpaceParams::NEGMEDIUM:
-               os << (runparams.free_spacing ? " " : "\\negmedspace{}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\negmedspace{}");
                break;
        case InsetSpaceParams::NEGTHICK:
-               os << (runparams.free_spacing ? " " : "\\negthickspace{}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\negthickspace{}");
                break;
        case InsetSpaceParams::HFILL:
-               os << (runparams.free_spacing ? " " : "\\hfill{}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\hfill{}");
                break;
        case InsetSpaceParams::HFILL_PROTECTED:
-               os << (runparams.free_spacing ? " " : "\\hspace*{\\fill}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\hspace*{\\fill}");
                break;
        case InsetSpaceParams::DOTFILL:
-               os << (runparams.free_spacing ? " " : "\\dotfill{}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\dotfill{}");
                break;
        case InsetSpaceParams::HRULEFILL:
-               os << (runparams.free_spacing ? " " : "\\hrulefill{}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\hrulefill{}");
                break;
        case InsetSpaceParams::LEFTARROWFILL:
-               os << (runparams.free_spacing ? " " : "\\leftarrowfill{}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\leftarrowfill{}");
                break;
        case InsetSpaceParams::RIGHTARROWFILL:
-               os << (runparams.free_spacing ? " " : "\\rightarrowfill{}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\rightarrowfill{}");
                break;
        case InsetSpaceParams::UPBRACEFILL:
-               os << (runparams.free_spacing ? " " : "\\upbracefill{}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\upbracefill{}");
                break;
        case InsetSpaceParams::DOWNBRACEFILL:
-               os << (runparams.free_spacing ? " " : "\\downbracefill{}");
+               os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\downbracefill{}");
                break;
        case InsetSpaceParams::CUSTOM:
-               if (runparams.free_spacing)
+               if (runparams.find_effective())
+                       os.put(0x00a0);
+               else if (runparams.free_spacing)
                        os << " ";
                else
                        os << "\\hspace{" << from_ascii(params_.length.asLatexString()) << "}";
                break;
        case InsetSpaceParams::CUSTOM_PROTECTED:
-               if (runparams.free_spacing)
+               if (runparams.find_effective())
+                       os.put(0x00a0);
+               else if (runparams.free_spacing)
                        os << " ";
                else
                        os << "\\hspace*{" << from_ascii(params_.length.asLatexString()) << "}";
@@ -699,72 +774,61 @@ int InsetSpace::plaintext(odocstringstream & os,
 }
 
 
-int InsetSpace::docbook(odocstream & os, OutputParams const &) const
+void InsetSpace::docbook(XMLStream & xs, OutputParams const &) const
 {
        switch (params_.kind) {
        case InsetSpaceParams::NORMAL:
-               os << " ";
+               xs << XMLStream::ESCAPE_NONE << " ";
                break;
        case InsetSpaceParams::QUAD:
-               os << "&emsp;";
+               xs << XMLStream::ESCAPE_NONE << "&#x2003;"; // HTML: &emsp;
                break;
        case InsetSpaceParams::QQUAD:
-               os << "&emsp;&emsp;";
+               xs << XMLStream::ESCAPE_NONE << "&#x2003;&#x2003;"; // HTML: &emsp;&emsp;
                break;
        case InsetSpaceParams::ENSKIP:
-               os << "&ensp;";
+               xs << XMLStream::ESCAPE_NONE << "&#x2002;"; // HTML: &ensp;
                break;
        case InsetSpaceParams::PROTECTED:
-               os << "&nbsp;";
+               xs << XMLStream::ESCAPE_NONE << "&#xA0;"; // HTML: &nbsp;
                break;
        case InsetSpaceParams::VISIBLE:
-               os << "&#x2423;";
+               xs << XMLStream::ESCAPE_NONE << "&#x2423;";
                break;
-       case InsetSpaceParams::ENSPACE:
-               os << "&#x2060;&ensp;&#x2060;";
+       case InsetSpaceParams::ENSPACE: // HTML: &#x2060;&ensp;&#x2060; (word joiners)
+               xs << XMLStream::ESCAPE_NONE << "&#x2060;&#x2002;&#x2060;";
                break;
        case InsetSpaceParams::THIN:
-               os << "&thinsp;";
+               xs << XMLStream::ESCAPE_NONE << "&#x2009;"; // HTML: &thinspace;
                break;
        case InsetSpaceParams::MEDIUM:
-               os << "&emsp14;";
+               xs << XMLStream::ESCAPE_NONE << "&#x2005;"; // HTML: &emsp14;
                break;
        case InsetSpaceParams::THICK:
-               os << "&emsp13;";
+               xs << XMLStream::ESCAPE_NONE << "&#x2004;"; // HTML: &emsp13;
                break;
        case InsetSpaceParams::NEGTHIN:
        case InsetSpaceParams::NEGMEDIUM:
        case InsetSpaceParams::NEGTHICK:
-               // FIXME
-               os << "&nbsp;";
+               xs << XMLStream::ESCAPE_NONE << "&#xA0;"; // HTML: &nbsp;
                break;
        case InsetSpaceParams::HFILL:
        case InsetSpaceParams::HFILL_PROTECTED:
-               os << '\n';
-               break;
        case InsetSpaceParams::DOTFILL:
-               // FIXME
-               os << '\n';
-               break;
        case InsetSpaceParams::HRULEFILL:
-               // FIXME
-               os << '\n';
-               break;
        case InsetSpaceParams::LEFTARROWFILL:
        case InsetSpaceParams::RIGHTARROWFILL:
        case InsetSpaceParams::UPBRACEFILL:
        case InsetSpaceParams::DOWNBRACEFILL:
        case InsetSpaceParams::CUSTOM:
        case InsetSpaceParams::CUSTOM_PROTECTED:
-               // FIXME
-               os << '\n';
+               xs << '\n';
                break;
        }
-       return 0;
 }
 
 
-docstring InsetSpace::xhtml(XHTMLStream & xs, OutputParams const &) const
+docstring InsetSpace::xhtml(XMLStream & xs, OutputParams const &) const
 {
        string output;
        switch (params_.kind) {
@@ -824,15 +888,25 @@ docstring InsetSpace::xhtml(XHTMLStream & xs, OutputParams const &) const
                break;
        }
        // don't escape the entities!
-       xs << XHTMLStream::ESCAPE_NONE << from_ascii(output);
+       xs << XMLStream::ESCAPE_NONE << from_ascii(output);
        return docstring();
 }
 
 
 void InsetSpace::validate(LaTeXFeatures & features) const
 {
-       if (params_.kind == InsetSpaceParams::NEGMEDIUM ||
-           params_.kind == InsetSpaceParams::NEGTHICK) 
+       if (features.isAvailable("LaTeX-2020/10/01"))
+               // As of this version, the LaTeX kernel
+               // includes all spaces.
+               return;
+
+       // In earlier versions, we require amsmath
+       // for some text and math spaces
+       if ((params_.kind == InsetSpaceParams::NEGMEDIUM
+            || params_.kind == InsetSpaceParams::NEGTHICK)
+           || (!params_.math
+               && (params_.kind == InsetSpaceParams::MEDIUM
+                   || params_.kind == InsetSpaceParams::THICK)))
                features.require("amsmath");
 }
 
@@ -845,7 +919,7 @@ void InsetSpace::toString(odocstream & os) const
 }
 
 
-void InsetSpace::forOutliner(docstring & os, size_t) const
+void InsetSpace::forOutliner(docstring & os, size_t const, bool const) const
 {
        // There's no need to be cute here.
        os += " ";