+
+/* Any property might be front-sticky on the left, rear-sticky on the left,
+ front-sticky on the right, or rear-sticky on the right; the 16 combinations
+ can be arranged in a matrix with rows denoting the left conditions and
+ columns denoting the right conditions:
+ _ __ _
+_ FR FR FR FR
+FR__ 0 1 2 3
+ _FR 4 5 6 7
+FR 8 9 A B
+ FR C D E F
+
+ left-props = '(front-sticky (p8 p9 pa pb pc pd pe pf)
+ rear-nonsticky (p4 p5 p6 p7 p8 p9 pa pb)
+ p0 L p1 L p2 L p3 L p4 L p5 L p6 L p7 L
+ p8 L p9 L pa L pb L pc L pd L pe L pf L)
+ right-props = '(front-sticky (p2 p3 p6 p7 pa pb pe pf)
+ rear-nonsticky (p1 p2 p5 p6 p9 pa pd pe)
+ p0 R p1 R p2 R p3 R p4 R p5 R p6 R p7 R
+ p8 R p9 R pa R pb R pc R pd R pe R pf R)
+
+ We inherit from whoever has a sticky side facing us. If both sides
+ do (cases 2, 3, E, and F), then we inherit from whichever side has a
+ non-nil value for the current property. If both sides do, then we take
+ from the left.
+
+ When we inherit a property, we get its stickiness as well as its value.
+ So, when we merge the above two lists, we expect to get this:
+
+ result = '(front-sticky (p6 p7 pa pb pc pd pe pf)
+ rear-nonsticky (p6 pa)
+ p0 L p1 L p2 L p3 L p6 R p7 R
+ pa R pb R pc L pd L pe L pf L)
+
+ The optimizable special cases are:
+ left rear-nonsticky = nil, right front-sticky = nil (inherit left)
+ left rear-nonsticky = t, right front-sticky = t (inherit right)
+ left rear-nonsticky = t, right front-sticky = nil (inherit none)
+*/
+
+Lisp_Object
+merge_properties_sticky (pleft, pright)
+ Lisp_Object pleft, pright;
+{
+ register Lisp_Object props, front, rear;
+ Lisp_Object lfront, lrear, rfront, rrear;
+ register Lisp_Object tail1, tail2, sym, lval, rval, cat;
+ int use_left, use_right;
+ int lpresent;
+
+ props = Qnil;
+ front = Qnil;
+ rear = Qnil;
+ lfront = textget (pleft, Qfront_sticky);
+ lrear = textget (pleft, Qrear_nonsticky);
+ rfront = textget (pright, Qfront_sticky);
+ rrear = textget (pright, Qrear_nonsticky);
+
+ /* Go through each element of PRIGHT. */
+ for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (Fcdr (tail1)))
+ {
+ Lisp_Object tmp;
+
+ sym = Fcar (tail1);
+
+ /* Sticky properties get special treatment. */
+ if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
+ continue;
+
+ rval = Fcar (Fcdr (tail1));
+ for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (Fcdr (tail2)))
+ if (EQ (sym, Fcar (tail2)))
+ break;
+
+ /* Indicate whether the property is explicitly defined on the left.
+ (We know it is defined explicitly on the right
+ because otherwise we don't get here.) */
+ lpresent = ! NILP (tail2);
+ lval = (NILP (tail2) ? Qnil : Fcar (Fcdr (tail2)));
+
+ /* Even if lrear or rfront say nothing about the stickiness of
+ SYM, Vtext_property_default_nonsticky may give default
+ stickiness to SYM. */
+ tmp = Fassq (sym, Vtext_property_default_nonsticky);
+ use_left = (lpresent
+ && ! (TMEM (sym, lrear)
+ || CONSP (tmp) && ! NILP (XCDR (tmp))));
+ use_right = (TMEM (sym, rfront)
+ || (CONSP (tmp) && NILP (XCDR (tmp))));
+ if (use_left && use_right)
+ {
+ if (NILP (lval))
+ use_left = 0;
+ else if (NILP (rval))
+ use_right = 0;
+ }
+ if (use_left)
+ {
+ /* We build props as (value sym ...) rather than (sym value ...)
+ because we plan to nreverse it when we're done. */
+ props = Fcons (lval, Fcons (sym, props));
+ if (TMEM (sym, lfront))
+ front = Fcons (sym, front);
+ if (TMEM (sym, lrear))
+ rear = Fcons (sym, rear);
+ }
+ else if (use_right)
+ {
+ props = Fcons (rval, Fcons (sym, props));
+ if (TMEM (sym, rfront))
+ front = Fcons (sym, front);
+ if (TMEM (sym, rrear))
+ rear = Fcons (sym, rear);
+ }
+ }
+
+ /* Now go through each element of PLEFT. */
+ for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (Fcdr (tail2)))
+ {
+ Lisp_Object tmp;
+
+ sym = Fcar (tail2);
+
+ /* Sticky properties get special treatment. */
+ if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
+ continue;
+
+ /* If sym is in PRIGHT, we've already considered it. */
+ for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (Fcdr (tail1)))
+ if (EQ (sym, Fcar (tail1)))
+ break;
+ if (! NILP (tail1))
+ continue;
+
+ lval = Fcar (Fcdr (tail2));
+
+ /* Even if lrear or rfront say nothing about the stickiness of
+ SYM, Vtext_property_default_nonsticky may give default
+ stickiness to SYM. */
+ tmp = Fassq (sym, Vtext_property_default_nonsticky);
+
+ /* Since rval is known to be nil in this loop, the test simplifies. */
+ if (! (TMEM (sym, lrear) || (CONSP (tmp) && ! NILP (XCDR (tmp)))))
+ {
+ props = Fcons (lval, Fcons (sym, props));
+ if (TMEM (sym, lfront))
+ front = Fcons (sym, front);
+ }
+ else if (TMEM (sym, rfront) || (CONSP (tmp) && NILP (XCDR (tmp))))
+ {
+ /* The value is nil, but we still inherit the stickiness
+ from the right. */
+ front = Fcons (sym, front);
+ if (TMEM (sym, rrear))
+ rear = Fcons (sym, rear);
+ }
+ }
+ props = Fnreverse (props);
+ if (! NILP (rear))
+ props = Fcons (Qrear_nonsticky, Fcons (Fnreverse (rear), props));
+
+ cat = textget (props, Qcategory);
+ if (! NILP (front)
+ &&
+ /* If we have inherited a front-stick category property that is t,
+ we don't need to set up a detailed one. */
+ ! (! NILP (cat) && SYMBOLP (cat)
+ && EQ (Fget (cat, Qfront_sticky), Qt)))
+ props = Fcons (Qfront_sticky, Fcons (Fnreverse (front), props));
+ return props;
+}
+