    //=============================================================================
    //  MuseScore
    //  Music Composition & Notation
    //
    //  Copyright (C) 2010-2011 Werner Schweer
    //
    //  This program is free software; you can redistribute it and/or modify
    //  it under the terms of the GNU General Public License version 2
    //  as published by the Free Software Foundation and appearing in
    //  the file LICENCE.GPL
    //=============================================================================

    #include "stem.h"
    #include "staff.h"
    #include "chord.h"
    #include "score.h"
    #include "stafftype.h"
    #include "hook.h"
    #include "tremolo.h"
    #include "note.h"
    #include "xml.h"

    // TEMPORARY HACK!!
    #include "sym.h"
    // END OF HACK

    namespace Ms {

    //---------------------------------------------------------
    //   Stem
    //    Notenhals
    //---------------------------------------------------------

    Stem::Stem(Score* s)
       : Element(s)
          {
          setFlags(ElementFlag::SELECTABLE);
          _lineWidth = score()->styleS(StyleIdx::stemWidth).val() * spatium();
          }

    //---------------------------------------------------------
    //   up
    //---------------------------------------------------------

    bool Stem::up() const
          {
          return chord() ? chord()->up() : true;
          }

    //---------------------------------------------------------
    //   stemLen
    //---------------------------------------------------------

    qreal Stem::stemLen() const
          {
          return up() ? -_len : _len;
          }

    //-------------------------------------------------------------------
    //   layout
    //    For beamed notes this is called twice. The final stem
    //    length can only be calculated after stretching of the measure.
    //    We need a guessed stem shape to calculate the minimal distance
    //    between segments. The guessed stem must have at least the
    //    right direction.
    //-------------------------------------------------------------------

    void Stem::layout()
          {
          qreal l    = _len + _userLen;
          qreal _up  = up() ? -1.0 : 1.0;
          l         *= _up;

          qreal y1 = 0.0;                           // vertical displacement to match note attach point
          Staff* stf = staff();
          if (chord()) {
                int tick = chord()->tick();
                StaffType* st = stf->staffType(tick);
                if (st->isTabStaff() ) {            // TAB staves
                      if (st->stemThrough()) {
                            // if stems through staves, gets Y pos. of stem-side note relative to chord other side
                            qreal lineDist = st->lineDistance().val() * spatium();
                            y1             = (chord()->downString() - chord()->upString()) * _up * lineDist;
                            // if fret marks above lines, raise stem beginning by 1/2 line distance
                            if (!st->onLines())
                                  y1 -= lineDist * 0.5;
                            // shorten stem by 1/2 lineDist to clear the note and a little more to keep 'air' betwen stem and note
                            lineDist *= 0.7 * mag();
                            y1       += _up * lineDist;
                            }
                      // in other TAB types, no correction
                      }
                else {                              // non-TAB
                      // move stem start to note attach point
                      Note* n  = up() ? chord()->downNote() : chord()->upNote();
                      y1      += (up() ? n->stemUpSE().y() : n->stemDownNW().y());
                      rypos() = n->rypos();
                      }
                }

          qreal lw5 = _lineWidth * .5;

          line.setLine(0.0, y1, 0.0, l);

          // compute bounding rectangle
          QRectF r(line.p1(), line.p2());
          setbbox(r.normalized().adjusted(-lw5, -lw5, lw5, lw5));
          adjustReadPos();  // does not work if stem is layouted twice
          }

    //---------------------------------------------------------
    //   setLen
    //---------------------------------------------------------

    void Stem::setLen(qreal v)
          {
          _len = (v < 0.0) ? -v : v;
          layout();
          }

    //---------------------------------------------------------
    //   spatiumChanged
    //---------------------------------------------------------

    void Stem::spatiumChanged(qreal oldValue, qreal newValue)
          {
          _userLen = (_userLen / oldValue) * newValue;
          layout();
          }

    //---------------------------------------------------------
    //   draw
    //---------------------------------------------------------

    void Stem::draw(QPainter* painter) const
          {
          // hide if second chord of a cross-measure pair
          if (chord() && chord()->crossMeasure() == CrossMeasure::SECOND)
                return;

          Staff* st      = staff();
          StaffType* stt = st ? st->staffType(chord()->tick()) : 0;
          bool useTab    = stt && stt->isTabStaff();

          painter->setPen(QPen(curColor(), _lineWidth, Qt::SolidLine, Qt::RoundCap));
          painter->drawLine(line);

          if (!(useTab && chord()))
                return;

          // TODO: adjust bounding rectangle in layout() for dots and for slash
          qreal sp = spatium();
          bool _up = up();

          // slashed half note stem
          if (chord()->durationType().type() == TDuration::DurationType::V_HALF && stt->minimStyle() == TablatureMinimStyle::SLASHED) {
                // position slashes onto stem
                qreal y = _up ? -(_len+_userLen) + STAFFTYPE_TAB_SLASH_2STARTY_UP*sp : (_len+_userLen) - STAFFTYPE_TAB_SLASH_2STARTY_DN*sp;
                // if stems through, try to align slashes within or across lines
                if (stt->stemThrough()) {
                      qreal halfLineDist = stt->lineDistance().val() * sp * 0.5;
                      qreal halfSlashHgt = STAFFTYPE_TAB_SLASH_2TOTHEIGHT * sp * 0.5;
                      y = lrint( (y + halfSlashHgt) / halfLineDist) * halfLineDist - halfSlashHgt;
                      }
                // draw slashes
                qreal hlfWdt= sp * STAFFTYPE_TAB_SLASH_WIDTH * 0.5;
                qreal sln   = sp * STAFFTYPE_TAB_SLASH_SLANTY;
                qreal thk   = sp * STAFFTYPE_TAB_SLASH_THICK;
                qreal displ = sp * STAFFTYPE_TAB_SLASH_DISPL;
                QPainterPath path;
                for (int i = 0; i < 2; ++i) {
                      path.moveTo( hlfWdt, y);            // top-right corner
                      path.lineTo( hlfWdt, y+thk);        // bottom-right corner
                      path.lineTo(-hlfWdt, y+thk+sln);    // bottom-left corner
                      path.lineTo(-hlfWdt, y+sln);        // top-left corner
                      path.closeSubpath();
                      y += displ;
                      }
                painter->setBrush(QBrush(curColor()));
                painter->setPen(Qt::NoPen);
                painter->drawPath(path);
                }

          // dots
          // NOT THE BEST PLACE FOR THIS?
          // with tablatures and stems beside staves, dots are not drawn near 'notes', but near stems
          int nDots = chord()->dots();
          if (nDots > 0 && !stt->stemThrough()) {
                qreal x     = chord()->dotPosX();
                qreal y     = ( (STAFFTYPE_TAB_DEFAULTSTEMLEN_DN * 0.2) * sp) * (_up ? -1.0 : 1.0);
                qreal step  = score()->styleS(StyleIdx::dotDotDistance).val() * sp;
                for (int dot = 0; dot < nDots; dot++, x += step)
                      drawSymbol(SymId::augmentationDot, painter, QPointF(x, y));
                }
          }

    //---------------------------------------------------------
    //   write
    //---------------------------------------------------------

    void Stem::write(XmlWriter& xml) const
          {
          xml.stag("Stem");
          Element::writeProperties(xml);
          if (_userLen != 0.0)
                xml.tag("userLen", _userLen / spatium());
          xml.etag();
          }

    //---------------------------------------------------------
    //   read
    //---------------------------------------------------------

    void Stem::read(XmlReader& e)
          {
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "userLen")
                      _userLen = e.readDouble() * spatium();
                else if (tag == "subtype")        // obsolete
                      e.skipCurrentElement();
                else if (!Element::readProperties(e))
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   updateGrips
    //---------------------------------------------------------

    void Stem::updateGrips(EditData& ed) const
          {
          ed.grip[0].translate(pagePos() + line.p2());
          }

    //---------------------------------------------------------
    //   startEdit
    //---------------------------------------------------------

    void Stem::startEdit(EditData& ed)
          {
          ed.grips   = 1;
          ed.curGrip = Grip::START;
          undoPushProperty(P_ID::USER_LEN);
          }

    //---------------------------------------------------------
    //   editDrag
    //---------------------------------------------------------

    void Stem::editDrag(EditData& ed)
          {
          qreal yDelta = ed.delta.y();
          _userLen += up() ? -yDelta : yDelta;
          layout();
          Chord* c = chord();
          if (c->hook())
                c->hook()->move(QPointF(0.0, ed.delta.y()));
          }

    //---------------------------------------------------------
    //   reset
    //---------------------------------------------------------

    void Stem::reset()
          {
          undoChangeProperty(P_ID::USER_LEN, 0.0);
          Element::reset();
          }

    //---------------------------------------------------------
    //   acceptDrop
    //---------------------------------------------------------

    bool Stem::acceptDrop(EditData& data) const
          {
          Element* e = data.element;
          if ((e->type() == ElementType::TREMOLO) && (static_cast<Tremolo*>(e)->tremoloType() <= TremoloType::R64)) {
                return true;
                }
          return false;
          }

    //---------------------------------------------------------
    //   drop
    //---------------------------------------------------------

    Element* Stem::drop(EditData& data)
          {
          Element* e = data.element;
          Chord* ch  = chord();

          switch(e->type()) {
                case ElementType::TREMOLO:
                      e->setParent(ch);
                      score()->undoAddElement(e);
                      return e;
                default:
                      delete e;
                      break;
                }
          return 0;
          }

    //---------------------------------------------------------
    //   getProperty
    //---------------------------------------------------------

    QVariant Stem::getProperty(P_ID propertyId) const
          {
          switch(propertyId) {
                case P_ID::USER_LEN: return userLen();
                default:
                      return Element::getProperty(propertyId);
                }
          }

    //---------------------------------------------------------
    //   setProperty
    //---------------------------------------------------------

    bool Stem::setProperty(P_ID propertyId, const QVariant& v)
          {
          switch (propertyId) {
                case P_ID::USER_LEN:
                      setUserLen(v.toDouble());
                      break;
                default:
                      return Element::setProperty(propertyId, v);
                }
          triggerLayout();
          return true;
          }

    //---------------------------------------------------------
    //   hookPos
    //    in chord coordinates
    //---------------------------------------------------------

    QPointF Stem::hookPos() const
          {
          QPointF p(pos() + line.p2());

          qreal xoff = _lineWidth * .5;
          p.rx() += xoff;
          return p;
          }

    }

↑ V595 The 'chord()' pointer was utilized before it was verified against nullptr. Check lines: 142, 148.